加载内容
右侧的文章内容区域封装成了一个组件。在components目录下新建daily-article.vue组件,它唯一接收唯一的一个prop:id,也就是文章的id,如果id变化了,就说明切换了文章,需要请求新的文章内容。
在app.vue中导入daily-article.vue组件,并在文章列表的Item组件上绑定查看文章事件
//app.vue
<template>
<div class="daily">
<div class="daily-menu">
</div>
<div class="daily-list" ref="list">
<template v-if="tyep==='recommend'">
<div v-for="list in recommendList">
<div class="daily-date">{{formatDay(list.date)}}</div>
<Item
@click.native="handleClick(time.id)"
v-for="item in list.stories"
:data="item"
:key="item.id"></Item>
</div>
</template>
<template v-if="type==='daily'">
<Item
@click.native="handleClick(time.id)"
v-for="item in list"
:data="item"
:key="item.id"></Item>
</template>
</div>
<daily-article :id="articleId"></daily-article>
</div>
</template>
<script>
import $ from './libs/util';
import Item from './components/item.vue';
import dailyArticle from './components/daily-article.vue';
export default{
components:{Item,dailyArticle},
data(){
return {
themes:[],
showTheme:false,
type:'recommend',
recommendList:[],
list:[],
dailyTime:$.getTodayTime(),
isLoading:false,
articleId:0
}
},
methods:{
handleClick(id){
this.articleId = id;
}
}
}
</script>
Item是组件,绑定原生事件时要带事件修饰符.native,否则会认为监听的是来自Item组件的定义事件click。
dailyArticle组件在监听到id改变时请求文章内容:
//components/daily-article.vue
<template>
<div class="daily-article">
<div class="daily-article-title">{{data.title}}</div>
<div class="daily-article-content" v-html="data.body"></div>
</div>
</template>
<script>
import $ from '../libs/util';
export default{
props:{
id:{
type:Number,
default:0
}
},
data(){
return {
data:{}
}
},
methods:{
getArticle(){
$.ajax.get('new/'+this.id).then(res=>{
//将文章中的图片地址替换为代理的地址
res.body = res.body.replace(/src="http/g,'src="'+$.imgPath+'http');
res.body = res.body.replace(/src="https/g,'src="'+$.imgPath+'https');
this.data = res;
//返回文章顶部
window.scrollTo(0,0);
})
}
},
watch:{
id(val){
if(val)this.getArticle();
}
}
};
</script>
//style.css
.daily-article{
margin-left: 450px;
padding: 20px;
}
.daily-article-title{
font-size: 28px;
font-weight: bold;
color: #222;
padding: 10px 0;
}
.view-more a{
display: block;
cursor: pointer;
background: #f5f7f9;
text-align: center;
color: inherit;
text-decoration: none;
padding: 4px 0;
border-radius: 3px;
}
加载评论
每条评论要显示发表时间,源数据格式为时间戳,需要前端转为相对时间。在daily目录下创建directives目录,并创建time.js文件
//directives/time.js
var Time = {
//获取当前时间戳
getUnix:function(){
var date = new Date();
return date.getTime();
},
//获取今天0点0分0秒的时间戳
getTodayUnix:function(){
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
//获取今年1月1日0点0分0秒的时间戳
getYearUnix:function(){
var date = new Date();
date.setMonth(0);
date.setDate(1);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
//获取标准年月日
getLastDate:function(time){
var date = new Date(time);
var month = date.getMonth()+1<10?'0'+(date.getMonth()+1):date.getMonth()+1;
var day = date.getDate()<10?'0'+date.getDate():date.getDate();
return date.getFullYear()+'-'+month+'-'+day;
},
//转换时间
getFormatTime:function(timestamp){
var now = this.getUnix();
var today = this.getTodayUnix();
var year = this.getYearUnix();
var timer =(now-timestamp)/1000;
var tip = '';
if(timer<=0){
tip='刚刚';
}else if(Math.floor(timer/60)<=0){
tip='刚刚';
}else if(timer<3600){
tip = Math.floor(timer/60)+'分钟前';
}else if(timer>=3600&&(timestamp-today>=0)){
tip = Math.floor(timer/3600)+'小时前';
}else if(timer/86400<=31){
tip = Math.ceil(timer/86400)+'天前';
}else{
tip = this.getLastDate(timestamp);
}
return tip;
}
};
export default{
bind:function(el,binding){
el.innerHTML = Time.getFormatTime(binding.value*1000);
el.__timeout__ = setInterval(function(){
el.innerHTML = Time.getFormatTime(binding.value*1000);
},60000);
},
unbind:function(el){
clearInterval(el.__timeout__);
delete el.__timeout__;
}
}
//components/daily-article.vue
<template>
<div class="daily-article">
<div class="daily-article-title">{{data.title}}</div>
<div class="daily-article-content" v-html="data.body"></div>
<div class="daily-comments" v-show="comments.length">
<span>评论({{comments.length}})</span>
<div class="daily-comment" v-for="comment in comments">
<div class="daily-comment-avatar">
<img :src="comment.avator">
</div>
<div class="daily-comment-content">
<div class="daily-comment-name">{{comment.author}}</div>
<div class="daily-comment-time" v-time="comment.time"></div>
<div class="daily-comment-text">{{comment.content}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Time from '../directives/time';
import $ from '../libs/util';
export default{
directives:{Time},
props:{
id:{
type:Number,
default:0
}
},
data(){
return {
data:{},
comments:[]
}
},
methods:{
getArticle(){
$.ajax.get('new/'+this.id).then(res=>{
//将文章中的图片地址替换为代理的地址
res.body = res.body.replace(/src="http/g,'src="'+$.imgPath+'http');
res.body = res.body.replace(/src="https/g,'src="'+$.imgPath+'https');
this.data = res;
//返回文章顶部
window.scrollTo(0,0);
this.getComments();
})
},
getComments(){
this.comments=[];
$.ajax.get('story/'+this.id+'/short-comments').then(res=>{
this.comments = res.comments.map(comment=>{
//将头像的图片地址转为代理地址
comment.avatar = $.imgPath+comment.avatar;
return comment;
});
})
}
},
watch:{
id(val){
if(val)this.getArticle();
}
}
};
</script>
style.css
.daily-comments{
margin:10px 0;
}
.daily-comments span{
display: block;
margin: 10px 0;
font-size: 20px;
}
.daily-comment{
overflow: hidden;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px dashed #e3e8ee;
}
.daily-comment-avatar{
width: 50px;
height: 50px;
float:left;
}
.daily-comment-avatar img{
width: 100%;
height: 100%;
border-radius: 3px;
}
.daily-comment-content{
margin-left: 65px;
}
.daily-comment-name{
}
.daily-comment-time{
color: #9ea7b4;
font-size: 14px;
margin-top:5px;
}
.daily-comment-text{
margin-top: 10px;
}