乐趣区

VueCliNodemongodb打造个人博客含前台展示及后台管理系统中

前言

前文:VueCli+Node+mongodb 打造个人博客(含前台展示及后台管理系统)(上)
https://segmentfault.com/a/11…

github 地址:https://github.com/ssevenk/ss…

在上篇文章中
我们完成了后端的配置,实现了对数据的增删查改
现在只需要前端页面发送对应的请求给后端即可

引入 axios

在开始搭建组件前,我们先要确定前端异步请求的方式
这里我用的是 axios
先在 main.js 中将其引入

import axios from 'axios'
Vue.prototype.$axios = axios;

这样我们就可以在自定义的组件中,直接用 this.$axios 来发起异步请求

后台管理系统

这里我把它分成了两个组件
管理组件(Manage.vue)以及编辑组件(Edit.vue)

管理组件(Manage.vue)

该组件的页面显示如图


核心部分就是那个表格了
用来展示已经存在的数据并对其进行操作

左侧导航

分成了三个类别,文章,杂谈和收藏
当我们点击对应的类别时,并没有在切换组件,而是在更新数据
Manage.vue
我们定义一个名叫 things 的空数组,来保存当前需要显示的数据
以及一个 kind 值,来保存当前需要显示的数据种类
我们先令 kind 值为blog,默认显示“文章”数据

data() {
return {
  kind: "blog",
  things: [],}

当组件初始化时,调用生命周期函数 created() 向后端发起对应种类的请求
后端返回对应的数据,存进 things 里面

    created() {this.getData("blog"); // 第一次默认先获取文章的数据
      },
    methods: {getData(kind) {
          this.kind = kind;
          this.$axios.get(`/data/${kind}`)
            .then(res => {this.things = res.data;})
     }

每次点击左侧的导航栏上的按钮,就调用一次 getData(),并传入对应的 kind 参数
由此来更新 thingskind
更新要显示的数据和种类
比如点击杂谈的话,就调用getData(essay)

数据表格

这里我用了 Element-ui 的组件库来制作表格
基本上就是官方案例


可以看到跟我的效果基本上一样
所以这部分可以直接参考官网教程 https://element.eleme.cn/#/zh…
在数据绑定的时候,选择我们之前建好的 things 数组

:data='things'

搜索

右上角有一个搜索输入框
输入后可以即时显示搜索的结果在数据表格里
一开始我想新定义一个 show 数组,来存放搜索后的结果
然后给输入框绑定键盘事件来调用搜索函数
但后来发现 Element 官网的做法异常简单
可以直接在 el-table 表格绑定的数据上做文章

:data="((things.filter(data=>!search||data.title.toLowerCase().includes(search.toLowerCase())“

其中 search 是双向绑定在输入框上的数据

分页

数据太多了肯定需要分页
还是用到了我们的 Element-ui 组件库

<el-pagination
        @current-change="handleCurrentChange"
        :page-size="pageSize"
        :current-page="currentPage"
        :total="things.length"
        layout="total, prev, pager, next"
      ></el-pagination>

PageSize 设置为 5,当前默认页为 1

data() {
return {
  kind: "blog",
  things: [],
  currentPage: 1,
  pageSize: 5,
  search: ""
};}

当点击页码切换的时候,把页码更新

handleCurrentChange(currentPage) {this.currentPage = currentPage;}

然后再一次对我们之前的 el-table 标签上的数据进行改进

:data="((things.filter(data=>!search||data.title.toLowerCase().includes(search.toLowerCase())).slice((currentPage-1)*pageSize,currentPage*pageSize)))"

这里的逻辑先后要理清
是先对数据进行搜索的过滤再分页

编辑组件(Edit.vue)

比起展示,更重要的还是对数据的操作
这里我把新建和编辑功能整合进了同一个组件里
因为都是利用 markdown 编辑器来编写
布局一模一样,只有初始化,按钮以及请求的方式不一样


关于这个 markdown 编辑器,我是利用的 simpleMDE
并添加了本来没有的本地上传图片功能
可以参见我的另一篇文章 https://segmentfault.com/a/11…
这里不再重复说明
其中在样式上,为了使编辑器高度控制在页面内,使滚动条出现在编辑器内而不是页面

.CodeMirror-scroll {
  min-height:350px;
  height: 350px;
}

添加这样的 css 样式(本来默认是 800px)

新建还是编辑?

Mangage 组件中点击了新建或者某篇文章的编辑按钮
我们就进入了这个 Edit 组件
因为整合在了同一个组件中
所以首先它得判断现在是要新建还是编辑
以及是要处理哪种数据,文章还是杂谈还是收藏?
建立一个 boolisNew和一个 stringkind
然后在生命周期函数 created() 中进行判断

  created() {
    this.kind = this.$route.params.kind;
    if (this.$route.params.id != "new") {this.isNew = false;}
  },

根据 Manage 组件路由跳转时传入的参数来判断
关于 vue-router 路由跳转,如果对 queryparams的用法有所疑问,可以参考我的这篇文章 https://segmentfault.com/a/11…

按钮

按钮给一个函数让其自行计算应该显示什么文字

computed: {btn: function() {switch (this.kind) {
    case "blog":
      return (this.isNew ? "发表" : "更新") + "文章";
    case "essay":
      return (this.isNew ? "发表" : "更新") + "杂谈";
    case "article":
      return (this.isNew ? "发表" : "更新") + "收藏";
    default:
      return "";
  }
}

如果是编辑

mounted() 周期函数中,请求后端的数据,来填入 markdown 编辑器的输入框

if (!this.isNew) {
      this.$axios
        .get(`/data/${this.$route.params.kind}/${this.$route.params.id}`)
        .then(req => {
          this.title = req.data.title;
          this.content = req.data.content;
          this.comments=req.data.comments;
          simplemde.value(this.content);
        });
    }

编辑完成后对后端的 post 请求

if (!this.isNew) {
        this.$axios
          .post(`/data/${this.$route.params.kind}/${this.$route.params.id}`, {
            id: this.$route.params.id,
            title: this.title,
            content: this.content
          })

如果是新建

需要给新文章一个创作日期

computed:{date: function() {var time = new Date(this.time);
          return `${(time.getMonth() + 1).toString().padStart(2, "0")}-${time
            .getDate()
            .toString()
            .padStart(2, "0")}`;
        }}

为了美观,用 padStart 来保证个位数日期也能以两位输出
post的时候,把日期也加上

 this.$axios
          .post(`/data/${this.$route.params.kind}/new`, {
            title: this.title,
            content: this.content,
            comments:this.comments,
            date: this.date
          })

删除数据

点击删除按钮的时候,获取到对应数据的 id 值并向后端传递
不过在这之前要先找到这个数据在 things 中的位置并删除
使用 findIndexsplice

del(delid) {
  var delIndex = this.things.findIndex(item => {return item._id == delid;});
  this.things.splice(delIndex, 1);
  this.$axios.delete(`/data/${this.kind}/${delid}`);
}

PS.

其实后来我又写了一个 EditArticle 组件出来
对应”收藏“,因为它只需要标题和跳转的链接,不需要编辑器
所以就单独为它写了一个,原理类同,这里不再赘述

接下来

完成了后台管理系统
我们就要开始做展示页面了
敬请期待后续文章

已更新第三篇:https://segmentfault.com/a/11…

退出移动版