array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 添加评论功能 - 爱码网

评论框:src/views/articles/Content.vue

 1 <!-- 评论框 -->
 2 <div >
 3   <div class="form-group comment-editor">
 4     <textarea v-if="auth" ></textarea>
 5     <textarea v-else disabled class="form-control" placeholder="需要登录后才能发表评论." style="height:172px"></textarea>
 6   </div>
 7   <div class="form-group reply-post-submit">
 8     <button >回复</button>
 9     <span class="help-inline">Ctrl+Enter</span>
10   </div>
11   <div v-show="commentHtml" ></div>
12 </div>

未登录时,我们显示一个被禁用的评论框:

HTML 格式的评论被保存在 commentHtml,我们使用 v-html 指令实时输出它:

2、在 created 钩子后面添加 mounted 钩子,我们在这里创建一个 SimpleMDE 编辑器的实例:

src/views/articles/Content.vue

 1 mounted() {
 2   // 已登录时,才开始创建
 3   if (this.auth) {
 4     // 自动高亮编辑器的内容
 5     window.hljs = hljs
 6 
 7     const simplemde = new SimpleMDE({
 8       element: document.querySelector('#editor'),
 9       placeholder: '请使用 Markdown 格式书写 ;-),代码片段黏贴时请注意使用高亮语法。',
10       spellChecker: false,
11       autoDownloadFontAwesome: false,
12       // 不显示工具栏
13       toolbar: false,
14       // 不显示状态栏
15       status: false,
16       renderingConfig: {
17         codeSyntaxHighlighting: true
18       }
19     })
20 
21     // 内容改变监听
22     simplemde.codemirror.on('change', () => {
23       // 更新 commentMarkdown 为编辑器的内容
24       this.commentMarkdown = simplemde.value()
25       // 更新 commentHtml,我们先替换原内容中的 emoji 标识,然后使用 markdown 方法将内容转成 HTML
26       this.commentHtml = simplemde.markdown(emoji.emojify(this.commentMarkdown, name => name))
27     })
28 
29     // 按键松开监听
30     simplemde.codemirror.on('keyup', (codemirror, event) => {
31       // 使用 Ctrl+Enter 时提交评论
32       if (event.ctrlKey && event.keyCode === 13) {
33         this.comment()
34       }
35     })
36 
37     // 将编辑器添加到当前实例
38     this.simplemde = simplemde
39   }
40 },

 

3.点击发表按钮时候的comment事件在 methods 选项中添加评论方法 comment

src/views/articles/Content.vue

 1 comment() {
 2   // 编辑器的内容不为空时
 3   if (this.commentMarkdown && this.commentMarkdown.trim() !== '') {
 4     // 分发 comment 事件以提交评论
 5     this.$store.dispatch('comment', {
 6       comment: { content: this.commentMarkdown },
 7       articleId: this.articleId
 8     }).then((comments) => {
 9       // 在浏览器的控制台打印返回的评论列表
10       console.log(comments)
11     })
12 
13     // 清空编辑器
14     this.simplemde.value('')
15     // 使回复按钮获得焦点
16     document.querySelector('#reply-btn').focus()
17   }
18 },

 

打开 src/store/actions.js 文件,在代码的最后面,导出评论事件 comment

src/store/actions.js

 1 .
 2 .
 3 .
 4 // 参数 articleId 是文章 ID;comment 是评论内容;commentId 是评论 ID
 5 export const comment = ({ commit, state }, { articleId, comment, commentId }) => {
 6   // 仓库的文章
 7   let articles = state.articles
 8   // 评论列表
 9   let comments = []
10 
11   if (!Array.isArray(articles)) articles = []
12 
13   for (let article of articles) {
14     // 找到对应文章时
15     if (parseInt(article.articleId) === parseInt(articleId)) {
16       // 更新评论列表
17       comments = Array.isArray(article.comments) ? article.comments : comments
18 
19       if (comment) {
20         // 获取用户传入的评论内容,设置用户 ID 的默认值为 1
21         const { uid = 1, content } = comment
22         const date = new Date()
23 
24         if (commentId === undefined) {
25           const lastComment = comments[comments.length - 1]
26 
27           // 新建 commentId
28           if (lastComment) {
29             commentId = parseInt(lastComment.commentId) + 1
30           } else {
31             commentId = comments.length + 1
32           }
33 
34           // 在评论列表中加入当前评论
35           comments.push({
36             uid,
37             commentId,
38             content,
39             date
40           })
41         }
42       }
43 
44       // 更新文章的评论列表
45       article.comments = comments
46       break
47     }
48   }
49 
50   // 提交 UPDATE_ARTICLES 以更新所有文章
51   commit('UPDATE_ARTICLES', articles)
52   // 返回评论列表
53   return comments
54 }

添加评论列表

1、打开 src/views/articles/Content.vue 文件,在 data 中添加 comments

src/views/articles/Content.vue

 1 data() {
 2   return {
 3     title: '', // 文章标题
 4     content: '', // 文章内容
 5     date: '', // 文章创建时间
 6     uid: 1, // 用户 ID
 7     likeUsers: [], // 点赞用户列表
 8     likeClass: '', // 点赞样式
 9     showQrcode: false, // 是否显示打赏弹窗
10     commentHtml: '', // 评论 HTML
11     comments: [], // 评论列表
12   }
13 },

2、修改 created 钩子(注释部分是涉及的修改):

src/views/articles/Content.vue 在页面渲染的时候将评论渲染出来

 1 created() {
 2   const articleId = this.$route.params.articleId
 3   const article = this.$store.getters.getArticleById(articleId)
 4 
 5   if (article) {
 6     // 获取文章的 comments
 7     let { uid, title, content, date, likeUsers, comments } = article
 8 
 9     this.uid = uid
10     this.title = title
11     this.content = SimpleMDE.prototype.markdown(emoji.emojify(content, name => name))
12     this.date = date
13     this.likeUsers = likeUsers || []
14     this.likeClass = this.likeUsers.some(likeUser => likeUser.uid === 1) ? 'active' : ''
15     // 渲染文章的 comments
16     this.renderComments(comments)
17 
18     this.$nextTick(() => {
19       this.$el.querySelectorAll('pre code').forEach((el) => {
20         hljs.highlightBlock(el)
21       })
22     })
23   }
24 
25   this.articleId = articleId
26 },

3、在 methods 选项中添加渲染评论方法 renderComments

src/views/articles/Content.vue

 1 renderComments(comments) {
 2   if (Array.isArray(comments)) {
 3     // 深拷贝 comments 以不影响其原值
 4     const newComments = comments.map(comment => ({ ...comment }))
 5     const user = this.user || {}
 6 
 7     for (let comment of newComments) {
 8       comment.uname = user.name
 9       comment.uavatar = user.avatar
10       // 将评论内容从 Markdown 转成 HTML
11       comment.content = SimpleMDE.prototype.markdown(emoji.emojify(comment.content, name => name))
12     }
13 
14     // 更新实例的 comments
15     this.comments = newComments
16     // 将 Markdown 格式的评论添加到当前实例
17     this.commentsMarkdown = comments
18   }
19 },

注:深拷贝 comments 是为了不影响已保存的文章,其方法等价于:

const newComments = comments.map(function (comment) {
  return Object.assign({}, comment)
})

上面的方法只处理了对象的第一层数据,当对象能被 JSON 解析时,可以使用下面的方法进行完整的深拷贝:

JSON.parse(JSON.stringify(comments))

4、修改 comment 评论方法(注释部分是涉及的修改):

src/views/articles/Content.vue

 1 comment() {
 2   if (this.commentMarkdown && this.commentMarkdown.trim() !== '') {
 3     this.$store.dispatch('comment', {
 4       comment: { content: this.commentMarkdown },
 5       articleId: this.articleId
 6     }).then(this.renderComments) // 在 .then 的回调里,调用 this.renderComments 渲染评论
 7 
 8     this.simplemde.value('')
 9     document.querySelector('#reply-btn').focus()
10 
11     // 将最后的评论滚动到页面的顶部
12     this.$nextTick(() => {
13       const lastComment = document.querySelector('#reply-list li:last-child')
14       if (lastComment) lastComment.scrollIntoView(true)
15     })
16   }
17 },

5、查找 <Modal ,在其后面添加『评论列表』:

src/views/articles/Content.vue

 1 <Modal :show.sync="showQrcode" class="text-center">
 2   .
 3   .
 4   .
 5 </Modal>
 6 
 7 <!-- 评论列表 -->
 8 <div class="replies panel panel-default list-panel replies-index">
 9   <div class="panel-heading">
10     <div class="total">
11       回复数量: <b>{{ comments.length }}</b>
12     </div>
13   </div>
14   <div class="panel-body">
15     <ul >
16       <li v-for="(comment, index) in comments" :key="comment.commentId" class="list-group-item media">
17         <div class="avatar avatar-container pull-left">
18           <router-link :to="`/${comment.uname}`">
19             <img :src="comment.uavatar" class="media-object img-thumbnail avatar avatar-middle">
20           </router-link>
21         </div>
22         <div class="infos">
23           <div class="media-heading">
24             <router-link :to="`/${comment.uname}`" class="remove-padding-left author rm-link-color">
25               {{ comment.uname }}
26             </router-link>
27             <div class="meta">
28               <a :>#{{ index + 1 }}</a>
29               <span> ⋅ </span>
30               <abbr class="timeago">
31                 {{ comment.date | moment('from', { startOf: 'second' }) }}
32               </abbr>
33             </div>
34           </div>
35 
36           <div class="preview media-body markdown-reply markdown-body" v-html="comment.content"></div>
37         </div>
38       </li>
39     </ul>
40     <div v-show="!comments.length" class="empty-block">
41       暂无评论~~
42     </div>
43   </div>
44 </div>

 

相关文章: