网站首页 » 前端开发 » Vue2+Koa2 搭建个人博客
上一篇:
下一篇:

Vue2+Koa2 搭建个人博客

前言

要用 Vue2+Koa2 开发一个博客系统不是什么难事,关键在于你得要有毅力,坚持到底,方能迎接伟大的胜利。不管做什么事,坚持不一定会有好很好的结果,但当你回头来看过去的这些经历时,你会突然发现,原来我已经做了那么多东西,虽然不是最好的,甚至跟别人比起来都不值得一起,但对于你息来说已经在不知不觉中得到了很大的提升。

在这篇文章中不会具体地从无到有说一篇,而是把在开发中的一些模块的用法,需要注意的地方,以及一些坑分享出来,让您少走弯路。

你可以学到

在这篇文章中从大的方面来说就是正如标题所说的你可以学到如果使用 Vue2 和 Koa2 来开发一个博客,从过程来说你可以学到以下内容:

  • 1、Vue2 在实践开发中的一些套路
  • 2、Vue2 的一些常用的模块
  • 3、Vue 基于 webpack 打包的一些优化
  • 4、Koa2 在实践开发中的一些套路
  • 5、Koa2 的一些常用的模块
  • 6、一些 Vue2 和 Kos2 中的坑

这篇文章涉及到的一些技术栈:

Vue2 中的有:

  • 1、Vuex
  • 2、Vue-router
  • 3、axios

Koa2 中的有:

  • 1、koa-static
  • 2、koa-bodyparser
  • 3、koa-jwt
  • 4、jsonwebtoken
  • 5、koa2-history-api-fallback
  • 6、bcrypt

数据库相关:

  • 1、mongodb
  • 2、mongoose

至于上面的一些模块是什么,要怎么用,我们后会说到。

开始 Vue2+Koa2 之旅

在这里我们前后端分开讲,这样阅读起来效果会好一些,不会那么混乱。

前端当然使用火得一塌糊涂的 Vue 框架,使用 vue-cli 脚手架来搭建前端项目目录,而对于前端主要分享如下内容:

  • 1、基本文件的建立(代码架构)
  • 2、vue-router 的路由优化
  • 3、Vue 打包后过大的优化

建立基本文件,通过 Vue-cli 建立好项目后,在 src 目录下新建如下目录(有则无需新增):

src
   ├── admin // 后台管理页面
   │  └── Edit.vue
   ├── api // 存放所有的后端请求
   │   ├── baseService.js // 请求的基本配置
   │   └── index.js  // 请求后台接口的方法
   ├── assets // 存放静态资源
   │   ├── imaages // 存放页面中用到的图片
   │   └── style // 存放样式文件
   ├── components // 存放组件
   │   ├── comment.vue
   │   ├── search.vue
   │   └── loading.vue
   ├── directives // 存放指令
   │   └── highlight
   ├── filters // 存放过滤器
   │   └── index.js
   ├── lib // 存放一些库
   │   └── index.js
   ├── pages // 存放页面
   │   └── home.vue
   ├── plugins // 存放 Vue 插件
   │   └── toast
   ├── router // 存放前端路由
   │   └── index.js
   ├── store // 存放状态管理
   │   ├── modules // 状态管理模块目录
   │   └── index.js modules 目录下的所有状态模块都在 index.js 文件中统一引入
   ├── utils // 存放工具类
   │   ├── localStorage.js
   │   └── detection.js
   ├── App.vue
   └── main.js

前端完成后,打包时,你会发现打包出来的文件有些很大,比如:vendor.js 有时甚至超过了 1M。要想把个文件减小,你可以做如下几件事。

1、打包时不生成 .map 文件,修改方法:把 src/config/index.js 文件中的 productionSourceMap 属性值改成 false。

2、把一些基础文件通过外部引用(比如:cdn),而不打包到 vendor.js 文件中。比如:vue.min.js、vue-router.min.js、vuex.min.js、highlight.min.js

在开发博客时,我使用了 highlight.min.js 使用代码高亮的处理库,本来也是直接打包到 vendor.js 中的,但打包到 vendor.js 中会让 vendor.js 的体积大了很多,所以才把它也分离出来。

对于第二步操作可以很明显地把 vendor.js 的体积降下来:不这里我记录下这个过程:

不优化直接打包 vendor.js 文件大小为:945 KB

把 vue.min.js、vue-router.min.js、vuex.min.js 从 vendor.js 中抽离出来来后 vendor.js 文件大小为:834 KB

使用路由懒加载(模块按需加载,只有当加载某个路由时,才会去加载这个路由所对应的模块)后,vendor.js 文件大小为:270 KB,可以看到路由懒加载还是很给力的,但因此而多出来一些路由模块中有两个文件那别地大,经过对比发现,一个是详情页,一个是发布页,布这两个页面的共同点就是都引入了一个代码高亮的指令,经过排除发现是引入了 highlight.min.js 文件导致了前面两个过大的事实。于是才决定也一同把 highlight.min.js 也抽离出去。

上面该抽离的都抽离完之后,除了 vendor.js 还是 270 KB 后,其它文件基本都是几KB 、十几二十 KB 的。你要知道从 900 多K 少到 200 多K,后打开页面的速度真的快了不少。我觉得如果条件允许,我们也应该这么做,把一些文件抽离 vendor.js ,通过 cdn 来加载这些资源。这样的好外如下:

1、cdn 加载资源更快。

2、浏览器可以同时加载多个资源,而如果都打包到 vendor.js,浏览器再牛逼也只能加载一个 vendor.js 并且必需等到这个 vendor.js 完全下载完之后,页面才可以渲染给用户。

就基于以上两点,我们就有足够的理由这么做了。

上面说到的把一些资源文件抽离 vendor.js,那么抽离了的资源要放到哪里呢?要怎么配置才实现这个效果呢?别急,就两步:

step 1:把抽离出来的资源在 index.html 中引入:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>博客系统</title>
</head>
<body>
  <div id="app"></div>
  <!-- built files will be auto injected -->
  <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
  <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
  <script src="https://cdn.bootcss.com/highlight.js/9.12.0/highlight.min.js"></script>
</body>
</html>

step 2:修改打包配置文件,打开 src/build/webpack.base.conf.js,在:module.exports = {} 中添加 externals 属性,具体代码如下:

module.exports = {
    ......
    // 添加下面的配置,不打包以下资源文件,我们使用网上的 cdn 来获取资源
    externals:{
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'vuex': 'Vuex',
        'highlight.js': 'hljs'
    }
}

操作完上两个步骤后,你就可以收获到部分资源抽离 vendor.js 后的快感了,快刷新页面看看效果如果!

下面是几个关键文件代码:

api/baseService.js

import axios from "axios";
import localStorage from "@/utils/localStorage";
const BaseService = axios.create({
  baseURL: "/", // 如果路由去使用了 history 模式,那么这里就需要设置下 baseURL,不然网站请求页面接口时会在当前路由后之追加请求接口,这就导致了请求路由不对。
  responseType: "json",
});

// 拦截请求
BaseService.interceptors.request.use(
  config => {
    // 从本地缓存中拿 token
    const token = localStorage.getItem("token");
    if (token) {
      // 将 token 设置到 headers 中,header 的 key 是 Authorization,注意值前面要带上 Bearer 并且 Bearer 后面要有空格
      config.headers.Authorization = "Bearer " + token;
    }
    return config
  },
  error => {
    return Promise.reject(error)
  });
  // 拦截直接返回 response.data 数据,其它不要
BaseService.interceptors.response.use(response => {
  return response.data
})

export default BaseService;

api/index.js

import BaseService from './baseService'

const getPostList = (pageInfo) => {
  return BaseService.get("api/getPostList", {
    params: {
      pageInfo
    }
  });
}

const getPostDetail = (id) => {
  return BaseService.get("api/getPostDetail", {
    params: {
      id: id
    }
  });
}

const removePostById = (id) => {
  return BaseService.get("api/removePostById", {
    params: {
      id: id
    }
  });
}

const savePost = (postVo) => {
  return BaseService.post("api/savePost", postVo);
}

export {
  getPostList,
  getPostDetail,
  removePostById,
  savePost
}

上面没有把所有的路由都晒出来,因为都是大同步异,主要是让你看看这些套路怎么串联起来。

下面我们就来看看如何使用状态管理,并建立不同的模块,及引入。

store/urlModule/index.js

const urlModule = {
  state: {
    url: {
      fullPath: "",
      params: {
        id: ""
      }
    }
  },
  // state 中定义的所有状态,都必需也只能通过 mutations 中的方法来进行修改,在其它组件中通过调用此方法来间接地修改 state 中的状态
  mutations: {
    setRediretUrl(state, params) {
      state.url.fullPath = params.fullPath;
    }
  }
}

export default urlModule;

store/userModule/index.js

import localStorage from '@/utils/localStorage';
// 定义一个状态管理容器
const userModule = {
  state: {
    user: {
      name: "",
    }
  },
  // state 中定义的所有状态,都必需也只能通过 mutations 中的方法来进行修改,在其它组件中通过调用此方法来间接地修改 state 中的状态
  mutations: {
    getUser(state) {
      const currentUser = localStorage.getItem("user");
      state.user.name = currentUser.name;
    }
  }
}

export default userModule;

在 store/index.js 中引入上面定义的两个状态模块。

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import userModule from '@/store/modules/userModule';
import urlModule from '@/store/modules/urlModule';
Vue.use(Vuex);
// 定义一个状态管理容器
let store = new Vuex.Store({
  modules: {
    userModule,
    urlModule
  }
});
export default store;

这样你就可以在不同的页面中通过形如 this.$store.state.userModule.user 来引用 userModule 模块下的 user 对象或者通过 this.$store.commit(“getUser”); 来执行状态模块中的方法。

directives/highlight/index.js

import Vue from 'vue'
// import hljs from "highlight.js";
import "./index.css"; //样式文件
Vue.directive('highlight', {
  inserted(el) {
    let blocks = el.querySelectorAll('pre code');
    blocks.forEach((block) => {
      hljs.highlightBlock(block);
    })
  },
})

由于前面我们已经把 highlight.js 抽出去了,所以在这里我们就不需要再引入了,即使不小心引入了也没关系,我们配置过 webpack ,所以 highlight.js 也不会被打包到 vendor.js 中。关于 highlight.js 的用法可以参考这里:https://highlightjs.org/

接下来就到后端出场了。

server
     ├── config
     │   └── Edit.vue
     ├── controllers
     │   ├── post.js
     │   └── user.js
     ├── services
     │   ├── post.js
     │   └── user.js
     ├── dao
     │   ├── post.js
     │   └── user.js
     ├── rouuters
     │   └── index.js
     ├── public
     │   └── uploads
     └── index.js

后端其实也没什么好说的,只是想说一些关于 koa2 在开发时很多人都会遇到的问题。至于后端代码要怎么写可以参考上面的结构目录。当然一些文件的命名可以根据自己的情况进行修改。下面我也会分享几个文件中的部分代码让你知道该如何写。

routers/index.js

const Router = require('koa-router');
Routers.post('/getCategorys', PostController.getCategorys);
module.exports = Routers;

controllers/post.js

const PostService = require('../services/post');
class PostController {
    static async getCategorys(ctx) {
      const response = await PostService.getCategorys();
      ctx.body = response;
    }
}
module.exports = PostController

services/post.js

const CodeConfig = require('../config/code-config');
const getCategorys = async () => {
    let response = {};
    const status = await postDao.getCategorys();
    response.code = status ? CodeConfig.success : CodeConfig.error;
    if (status) {
        response.data = status;
    }
    return response;
};
module.exports = {
  getCategorys
}

dao/post.js

const CategoryModel = require('../db/models/category');
const getCategorys = async () => {
    const categorys = await CategoryModel.find({}).sort({
        _id: -1
    }).exec();
    return categorys;
};
module.exports = {
  getCategorys
}

db/models/category.js

const db = require('../db');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

/*
 * @name 分类名
 * @status 用户状态,0 停用 1 启用
 */

const CategorySchema = new Schema({
  name: {
    type: String
  },
  status: {
    type: Number
  },
  createTime: {
    type: Date
  }
});

const CategoryModel = db.model('Category', CategorySchema);
module.exports = CategoryModel;

db/db.js

const mongoose = require('mongoose');
const dbUrl = "mongodb://localhost:27017/blog";
mongoose.connect(dbUrl);

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
  console.log("连接成功!");
});

module.exports = mongoose

到这里 Vue2+Koa2 开发一个博客系统的套路已经展示完成。

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/vue2-koa2-blog/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

评论 END