加载内容

右侧的文章内容区域封装成了一个组件。在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;
}

Vue.js入门 0x13 实战:知乎日报项目开发-文章详情页相关推荐

  1. vue设置cookie的domain无效_【Vue.js入门到实战教程】16Tailwind 与 Bootstrap 的区别和使用入门...

    来源 | https://xueyuanjun.com/post/22065我们知道,从 Laravel 8 开始,自带前端脚手架代码默认兼容 Tailwind CSS 框架,取代了之前的 Boots ...

  2. js模板字符串自定义类名_【Vue.js 入门到实战教程】07Vue 组件注册 | 基本使用和组件嵌套...

    来源 | https://xueyuanjun.com/post/21929除了前面介绍的基本语法之外,Vue.js 还支持通过组件构建复杂的功能模块,组件可以称得上是 Vue.js 的灵魂,是 Vu ...

  3. vue3项目实战---知乎日报----项目搭建

    目录 基础框架和响应式布局 项目介绍 接口文档 vue.config pagejson 初始化公共样式 vuex模块 路由模块 utils公共类库 axios 二次封装 响应式处理 && ...

  4. Vue+JS+Element UI实战(电商项目1)

    目录 1.电商业务概述 2.电商后台管理系统的功能 ​3.项目初始化步骤 4.后台项目的环境安装配置 4.1. API V1 接口说明 4.2. 支持的请求方法 4.3. 通用返回状态说明 5.测试后 ...

  5. Vue.js入门教程(适合初学者)

    Vue.js入门教程 Vue官网网址:Vue.js 中文网 Vue.js Vue.js是渐进式JavaScript 框架,是一套构建用户界面的渐进式框架.也可以说Vue.js 是一个用来构建网页界面的 ...

  6. Vue.js入门教程-组件注册

    一.组件创建 1.1 创建步骤 创建Vue的组件都有三个基本步骤是 [①创建组件构造器.②注册组件和③使用组件]. 1.2 基本示例 比如,我们创建一个Button组件. // 1. 创建一个组件构造 ...

  7. React.js 入门与实战课程思维导图

    原文发表于我的技术博客 我在慕课网的「React.js 入门与实战之开发适配PC端及移动端新闻头条平台」课程已经上线了,在这里分享了课程中的思维导图,供大家参考. 原文发表于我的技术博客 此导图为课程 ...

  8. React.js 入门与实战之开发适配PC端及移动端新闻头条平台课程上线了

    原文发表于我的技术博客 我在慕课网的「React.js 入门与实战之开发适配PC端及移动端新闻头条平台」课程已经上线了,文章中是目前整个课程的大纲,以后此课程还会保持持续更新,此大纲文档也会保持更新, ...

  9. Vue.js入门指南(一)

      前  言 JRedu 之前用过一段时间的AnglarJS 1.X,在低版本的AngularJS中,脏值检查在变量增多的情况下会影响程序的响应速度.后期的2.X和更高版本在脏值检查等问题上做了优化, ...

最新文章

  1. mysql 打开文件数_MySQL打开的文件描述符限制
  2. js实现数据结构及算法之二叉树(Binary Tree)
  3. 虚拟机下的CentOS环境中安装Node.js
  4. Discuz! 出现“您当前的访问请求当中含有非法字符“解决方法
  5. Markdown数学公式大全
  6. Facebook 实时聊天架构日均处理数十亿条消息!
  7. sql随机取一条数据
  8. win10键盘全变成快捷键_电脑键盘灵敏度设置方法
  9. 前端性能优化(三)——浏览器九大缓存方法
  10. 橙色——网页效果图设计之色彩索引
  11. win10系统截图快捷键
  12. c++语言程序中,main()函数必须放在程序开始的部分,C++多选题(附答案)
  13. 将word 转换为图片(word to pdf ->pdf to image)
  14. 计算机辅助教育相关论文,计算机辅助教育论文
  15. 动态拼图怎么做?如何将多张动图拼接在一起?
  16. 小觅双目摄像头标准彩色版发布 为移动机器人视觉导航避障优化设计
  17. 万物皆可集成系列:低代码释放用友深度价值(1)—系统对接集成
  18. 如何在面试中介绍自己的项目经验(面向java改进版)
  19. 热烈祝贺上汽通用五菱ASPICE项目通过CL 2级评估
  20. Linux: 宏:__stringify,字符串化传入参数

热门文章

  1. 用VLFeat库进行k-means聚类(C++ 实现)
  2. h5获取安卓定位_关于H5+ 安卓离线打包后,无法获取定位问题。
  3. 年度全球十大突破性技术公布;华为发布数字能源零碳网络解决方案 | 美通企业日报...
  4. Android和iOS应用下载实现合成一个二维码
  5. 太尴尬了,网关配置错误一直404
  6. 项目管理—编码流程及代码走查
  7. Leetcode上测试用例测试结果正确,但提交后有错的问题
  8. Java异常使用的一点心得
  9. 这些excel英语翻译方法你会吗?
  10. wps插入html,wps怎么插入脚注?