编辑文章

1). 添加编辑文章路由

打开 src/router/routes.js 文件,在数组的最后面,添加编辑文章路由 Edit

src/router/routes.js

1   // Edit
2   {
3     path: '/articles/:articleId/edit',
4     name: 'Edit',
5     component: () => import('@/views/articles/Create'),
6     meta: { auth: true }
7   },

我们这里使用了跟 Create 一样的组件页面,但将其路径指向一个新的地址,并命名为 Edit

2). 添加编辑入口

1、打开 src/views/articles/Content.vue 文件,复制以下代码替换原 <script>

src/views/articles/Content.vue

 1 <script>
 2 import SimpleMDE from 'simplemde'
 3 import hljs from 'highlight.js'
 4 import emoji from 'node-emoji'
 5 import { mapState } from 'vuex'
 6 
 7 export default {
 8   name: 'Content',
 9   data() {
10     return {
11       title: '', // 文章标题
12       content: '', // 文章内容
13       date: '', // 文章创建时间
14       uid: 1 // 用户 ID
15     }
16   },
17   computed: {
18     ...mapState([// 将仓库的以下状态混入到计算属性之中
19       'auth',
20       'user'
21     ])
22   },
23   created() {
24     const articleId = this.$route.params.articleId
25     const article = this.$store.getters.getArticleById(articleId)
27     if (article) {
28       let { uid, title, content, date } = article
30       this.uid = uid
31       this.title = title
32       this.content = SimpleMDE.prototype.markdown(emoji.emojify(content, name => name))
33       this.date = date
35       this.$nextTick(() => {
36         this.$el.querySelectorAll('pre code').forEach((el) => {
37           hljs.highlightBlock(el)
38         })
39       })
40     }
41 
42     this.articleId = articleId
43   },
44   methods: {
45     editArticle() {
46       this.$router.push({ name: 'Edit', params: { articleId: this.articleId } })
47     },
48     deleteArticle() {
49 
50     }
51   }
52 }
53 </script>

2、查找 <div class="markdown-body",在其后面添加『编辑删除图标』:

1 <div class="markdown-body" v-html="content"></div>
2 
3 <!-- 编辑删除图标 -->
4 <div v-if="auth && uid === 1" class="panel-footer operate">
5   <div class="actions">
6     <a @click="deleteArticle" class="admin" href="javascript:;"><i class="fa fa-trash-o"></i></a>
7     <a @click="editArticle" class="admin" href="javascript:;"><i class="fa fa-pencil-square-o"></i></a>
8   </div>
9 </div>

我们先判断用户是否已登录,已登录且当前用户 ID 为 1 时,渲染编辑删除图标。

3). 添加编辑文章逻辑

打开 src/store/actions.js 文件,复制以下代码替换原 post 事件:

src/store/actions.js

 1 export const post = ({ commit, state }, { article, articleId }) => {
 2   let articles = state.articles
 3 
 4   if (!Array.isArray(articles)) articles = []
 5 
 6   if (article) {
 7     const uid = 1
 8     const { title, content } = article
 9     const date = new Date()
10 
11     if (articleId === undefined) {
12       const lastArticle = articles[articles.length - 1]
13 
14       if (lastArticle) {
15         articleId = parseInt(lastArticle.articleId) + 1
16       } else {
17         articleId = articles.length + 1
18       }
19 
20       articles.push({
21         uid,
22         articleId,
23         title,
24         content,
25         date
26       })
27     }else { // 如果有传 articleId
28   // 遍历所有文章
29   for (let article of articles) {
30     // 找到与 articleId 对应的文章
31     if (parseInt(article.articleId) === parseInt(articleId)) {
32       // 更新文章的标题
33       article.title = title
34       // 更新文章的内容
35       article.content = content
36       break
37     }
38   }
39 }
40     commit('UPDATE_ARTICLES', articles)
41     router.push({ name: 'Content', params: { articleId, showMsg: true } })
42   }
43 }

4). 修改创作文章页面

1、打开 src/views/articles/Create.vue 文件,复制以下代码替换原 <script>

src/views/articles/Create.vue

 1 <script>
 2 import SimpleMDE from 'simplemde'
 3 import hljs from 'highlight.js'
 4 import ls from '@/utils/localStorage'
 5 
 6 window.hljs = hljs
 7 
 8 export default {
 9   name: 'Create',
10   data() {
11   return {
12     articleId: undefined // 文章 ID
13   }
14 },
15 beforeRouteEnter(to, from, next) {
16   next(vm => {
17     // 确认渲染组件的对应路由时,设置 articleId
18     vm.setArticleId(vm.$route.params.articleId)
19   })
20 },
21 // 在离开该组件的对应路由前
22 beforeRouteLeave(to, from, next) {
23   // 清空自动保存的文章数据
24   this.clearData()
25   next()
26 },
27 watch: {
28   // 监听路由参数的变化
29   '$route'(to) {
30     // 清空自动保存的文章数据
31     this.clearData()
32     // 设置 articleId
33     this.setArticleId(to.params.articleId)
34   }
35 },
36 methods: {
37   // 填充文章数据
38   fillContent(articleId) {
39     // 编辑器
40     const simplemde = this.simplemde
41     // 自动保存的标题
42     const smde_title = ls.getItem('smde_title')
43 
44     // 有 articleId 时
45     if (articleId !== undefined) {
46       // 获取对应文章
47       const article = this.$store.getters.getArticleById(articleId)
48 
49       if (article) {
50         // 获取文章的标题和内容
51         const { title, content } = article
52 
53         // 有自动保存的标题时,使用自动保存的标题,否则使用文章的标题
54         this.title = smde_title || title
55         // 有自动保存的内容时,使用自动保存的内容,否则使用文章的内容
56         this.content = simplemde.value() || content
57         // 设置编辑器的内容
58         simplemde.value(this.content)
59       }
60     } else { // 没有 articleId 时,使用自动保存的标题和内容
61       this.title = smde_title
62       this.content = simplemde.value()
63     }
64   },
65   post() {
66     if (title !== '' && content.trim() !== '') {
67       // 在分发 post 事件时,附带 articleId 参数
68       this.$store.dispatch('post', { article, articleId: this.articleId })
69     }
70   },
71   // 设置 articleId
72   setArticleId(articleId) {
73     // 获取 localStorage 保存的 articleId,临时用它来判断是否还处于当前编辑页面
74     const localArticleId = ls.getItem('articleId')
75 
76     // 手动在两个不同的编辑页面之间跳转时(如 /articles/1/edit 和 /articles/2/edit)时
77     if (articleId !== undefined && !(articleId === localArticleId)) {
78       // 清空自动保存的文章数据
79       this.clearData()
80     }
81 
82     // 设置当前实例的 articleId
83     this.articleId = articleId
84     // 填充文章数据
85     this.fillContent(articleId)
86     // 在 localStorage 保存一个 articleId
87     ls.setItem('articleId', articleId)
88   }
89 }
90 </script>

上面代码的核心就是利用路由参数的 articleId,获取对应的文章数据,来填充编辑页面。在不同的编辑页面之间跳转(如 /articles/1/edit 和 /articles/2/edit)时,因为我们会优先填充自动保存的数据,所以需要先调用 clearData 清空它们。

涉及的新知识点:

1 beforeRouteLeave(to, from, next) {
2   this.clearData()
3   next()
4 }

beforeRouteLeave 是组件内的守卫,在离开该组件的对应路由时调用,此时可以访问 this,需要使用 next() 确认导航。

监听 '$route'

1 watch: {
2   '$route'(to) {
3     this.clearData()
4     this.setArticleId(to.params.articleId)
5   }
6 }

我们可以通过监听 '$route' 来得知路由参数的变化,我们通常会在两个路由都渲染相同的组件时监听 '$route',这是因为 Vue 会复用组件实例,以导致组件内的部分钩子不再被调用。举例来说,我们的『编辑文章』和 『创作文章』都使用 Create.vue 组件,当我们从『编辑文章』导航到『创作文章』时(在编辑文章页面点击创作文章按钮),beforeRouteEnter 就不会被调用,所以我们需要监听 '$route',以响应路由参数的变化。

2、查找 <h2 class="text-center">,作如下修改:

1 <!-- 修改 -->
2 <h2 class="text-center">创作文章</h2>
3 <!-- 为 -->
4 <h2 class="text-center">{{ articleId ? '编辑文章' : '创作文章' }}</h2>

 

posted @ 2018-07-16 16:26  前端极客  阅读(768)  评论(0编辑  收藏  举报