评论框:src/views/articles/Content.vue
1 2
未登录时,我们显示一个被禁用的评论框:
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: true18 }19 })20 21 // 内容改变监听22 simplemde.codemirror.on('change', () => {23 // 更新 commentMarkdown 为编辑器的内容24 this.commentMarkdown = simplemde.value()25 // 更新 commentHtml,我们先替换原内容中的 emoji 标识,然后使用 markdown 方法将内容转成 HTML26 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 = simplemde39 }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 : comments18 19 if (comment) {20 // 获取用户传入的评论内容,设置用户 ID 的默认值为 121 const { uid = 1, content } = comment22 const date = new Date()23 24 if (commentId === undefined) {25 const lastComment = comments[comments.length - 1]26 27 // 新建 commentId28 if (lastComment) {29 commentId = parseInt(lastComment.commentId) + 130 } else {31 commentId = comments.length + 132 }33 34 // 在评论列表中加入当前评论35 comments.push({36 uid,37 commentId,38 content,39 date40 })41 }42 }43 44 // 更新文章的评论列表45 article.comments = comments46 break47 }48 }49 50 // 提交 UPDATE_ARTICLES 以更新所有文章51 commit('UPDATE_ARTICLES', articles)52 // 返回评论列表53 return comments54 }
添加评论列表
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: '', // 评论 HTML11 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 = uid10 this.title = title11 this.content = SimpleMDE.prototype.markdown(emoji.emojify(content, name => name))12 this.date = date13 this.likeUsers = likeUsers || []14 this.likeClass = this.likeUsers.some(likeUser => likeUser.uid === 1) ? 'active' : ''15 // 渲染文章的 comments16 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 = articleId26 },
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.avatar10 // 将评论内容从 Markdown 转成 HTML11 comment.content = SimpleMDE.prototype.markdown(emoji.emojify(comment.content, name => name))12 }13 14 // 更新实例的 comments15 this.comments = newComments16 // 将 Markdown 格式的评论添加到当前实例17 this.commentsMarkdown = comments18 }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
12 . 3 . 4 . 5 6 7 89101411 回复数量: { { comments.length }}12131544 4041 暂无评论~~4243