从零到一搭建Vue2后台管理系统

10,955 阅读9分钟

本文将从零到一实现一个基于Vue2+ElementUI的后台管理系统,《项目地址》让我们开始吧!

1.创建项目

使用Vue CLI创建项目,一手vue create vue2-element-admin走起!

我这里是配置了几个常用的配置项目,没有配置也没有关系,总之就是一步步选择下来,要选择的有 vue-router,vuex,node-sass,babel,eslint,回车,等待 install 完成即可。

进入到项目目录,yarn serve 启动服务即可,这里有一个小技巧,就是在原本的 serve 命令最后添加--open ,即可在服务启动完成后自动在浏览器打开页面。

package.json 如下:
{
  "name": "vue2-element-admin",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve --open",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-router": "^3.2.0",
    "vuex": "^3.4.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "node-sass": "^4.12.0",
    "sass-loader": "^8.0.2",
    "vue-template-compiler": "^2.6.11"
  }
}

接下来就是把不需要的文件及代码通通干掉,完成后项目目录如下:

2.新建vue.config.js,并添加基础配置

"use strict";
const path = require("path");
function resolve(dir) {
  return path.join(__dirname, dir);
}
// 端口号
const port = 8080;
module.exports = {
  // 部署应用包时的基本 URL
  publicPath: "./",
  // 项目打包输出目录
  outputDir: "dist",
  // 项目静态文件打包输出目录
  assetsDir: "static",
  // 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码。这个值会在 @vue/cli-plugin-eslint 被安装之后生效
  lintOnSave: process.env.NODE_ENV === "development",
  productionSourceMap: false,
  devServer: {
    port: port,
    open: false,
    https: false,
    hotOnly: false,
  },
  configureWebpack: {
    resolve: {
      // 配置快捷路径
      alias: {
        "@": resolve("src")
      }
    },
  },
};

3.引入ElementUI组件库

通过命令 yarn add element-ui 安装依赖,接下来在 main.js 添加以下代码,即可在项目中开心的使用ElemnetUI组件库了

import ElementUI from 'element-ui';import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)

4.基础页面编写

基本的页面包括首页,登录页面,以及基本的逻辑编写

这里对页面结构及样式不做过多赘述,只贴关键代码。

1.登录页面通过 ElementUI 的 form 组件编写即可,点击登录调用方法如下:

methods: {
  login(formName) {
    this.loginLoading = true;
    this.$refs[formName].validate((valid) => {
      if (valid) {
        this.$store.dispatch("user/login", this.param).then(() => {
          this.loginLoading = false;
          this.$router.push({ name: "Home" });
        });
      } else {
        return false;
      }
    });
  }
}

登录请求的操作我们给到了 store 里的 user 模块的 login action 去处理,在 user 模块,维护了用户的信息,在登录操作成功后将用户信息保存在 store 中,代码如下:

actions: {
  // 登录
  login({commit,dispatch},data){
    return new Promise((resolve) => {
      apiLogin(data).then(async res => {
        commit('SET_USER_INFO',res.body)
        resolve('success')
      })
    })
  }
}

上面代码中,调用了apiLogin方法发起请求,实际项目中,我会把所有接口请求方法放在src目录下的api文件夹中,并为每个模块创建对应的js文件维护该模块接口。

登录过程需要发起接口请求,vue项目中通常使用axios库

5.安装axios

通过命令yarn add axios安装依赖,并在src目录下新建utils管理我们的工具方法

在utils目录下新建requeset.js,封装axios,并向外暴露axios实例,这里我们可以通过请求拦截器及响应拦截器编写通用逻辑,并组建基本的请求体结构。

在搭建项目的时候,很多时候还没有后端接口给到前端,为了整体逻辑更接近实际项目过程,我们需要使用mockjs

6.安装mockjs

通过命令yarn add mockjs安装依赖,并在项目根目录创建mock文件夹,mock文件夹下新建index.js,所有的请求接口都会通过index.js暴露,为了更好的管理我们的接口,用户操作相关的接口放在user.js文件中,并在index.js引入user.js,登录mock代码如下:

// 引入mockjs
const Mock = require('mockjs')
// 登录
Mock.mock('/api/user/login', 'post', (req) => {
  const data = JSON.parse(req.body).body;
  return {
    header:{
      code:0
    },
    body:{
      busiId:'001',
      name:data.name,
      avatar:'https://img0.baidu.com/it/u=3233551726,336273710&fm=26&fmt=auto&gp=0.jpg'
    }
  }
})

引入mockjs 需要在 main.js 添加如下代码:

// 如果是开发环境,引入mock
process.env.NODE_ENV==='development'&&require('../mock/index')

至此,整个登录流程完成。

7.路由权限控制

通常,如果用户未登录的情况下访问后台管理系统且目标页面不是登录页面,需要将用户路由指向登录页面进行登录,这一步可以通过 vue-router 的路由前置守卫实现,代码如下:

// 路由前置守卫
router.beforeEach((to,from,next) =>{
  // 免登录白名单
  const whiteList = ['Login','NotFund'] 
 // 如果未登录 并且目标路由不在白名单
  if(!store.getters.userInfo.userId&&whiteList.indexOf(to.name)===-1) next({name:'Login'})
  else next()
})

这里我们用到了store.getters.userInfo.userId判断用户是否登录,实际项目中,大家可以根据实际项目需求进行该判断,比如判断 cookie,seesion 等。

并且在登录成功后,在 src/store/modules/permission.js 中进行了动态路由的添加,模拟登录成功后,动态添加该用户的权限路由。

这里的 getters 我编写了一个 getters.js 文件在 src/store 目录下,统一管理 strore 的getters,并在 store/index.js 中引入使用,代码如下:

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters
'import user from './modules/user'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {  },
  mutations: {  },
  actions: {  },
  getters,
  modules: {
    user
  }
})

8.页面主体框架

后台管理系统的整理内容框架一般如下图所示:

左侧为 logo 及菜单区,右侧顶部为控制菜单展开收起的按钮,当前页面的面包屑导航,用户头像,点击下拉一般会有用户信息,修改密码,退出登录等快捷入口及操作,以及当前已打开页面的页签列表。

在系统内点击左侧菜单切换页面的时候,页面主体框架是不变的,只有中间内容区切换展示对应业务页面,很自然的想到这一部分可以抽离出一个组件进行维护,业务页面通过 router-view 标签嵌套在主体框架中。

在项目中,以上功能可以通过路由嵌套实现,调整后的首页路由如下:

{
  path: '/',
  name: 'Root',
  redirect:'/home',
  component: Layout,
  children:[
    {
      path:'home',
      name:"Home",
      meta:{title:'首页},
      component:() => import('@/views/Home.vue')
    }
  ]
}

上面的 Layout 即为封装好的主体框架组件,Home.vue 代码如下:

<template>
  <div class="home pt_20 t_center fontsize_20">
    {{message}}
  </div>
</template>
<script>
export default {
  name: "Home",
  components: {},
  data() {
    return {
      message:'Welcome to vue2-elment-admin by wzy'
    };
  }
};
</script>

此时打开首页,即可看到如上图的首页内容。

接下来,我们就需要一步步编写 Layout 组件了

8-1.左侧logo

这一部分很简单,就是一个左右布局,并引入到左侧对应组件src/layout/components/SliderBar/index.vue

8-2.左侧菜单

这一部分相对复杂一点,src/layout/components/SliderBar/index.vue 为主体文件,使用 el-menu 组件,内部遍历 routes,根据是否有子路由,选择使用 el-submenu 或者 el-munu-item 组件生成菜单,需要注意的是这里的 Item 组件需要给定 name,以便 Item 组件递归自调用时使用。

SliderBar文件目录如下:

这里要说一下 el-menu 组件有一个 collapse 属性,控制菜单的展开收起,我们在 storesetting.js 模块中维护了这个状态

8-3.右侧Collapse组件

该组件控制切换 storesetting.jscollapse 属性切换,对应文件位置如下:

8-4.右侧面包屑导航

该组件动态展示当前页面路由,且当前页面的祖先路由可以点击进行跳转,对应文件位置如下:

8-5.右侧头像下拉

该组件展示登录用户的头像,点击展开下拉,显示用户信息,修改密码,退出登录等功能,对应文件位置如下:

8-6:右侧已访问路由列表

改组件展示用户已经访问的路由,并且右键显示刷新,关闭,关闭其他,关闭所有菜单,功能相对复杂一些,对应数据状态保存和修改方法在 src/store/modules/tagsView.js 中进行维护,对应文件位置如下:

通过路由后置守卫,将访问过的路由添加到 store/tagsView

至此,页面主体框架部分完成!

但是先不要高兴的太早,当登录成功进入首页后,一番操作,感觉十分丝滑,但是按下F5后,发现页面直接跳转到登录页面了,这是因为我们的项目是单页应用,登录信息放在了 store 下的 user 模块中,刷新后store 中的数据进行了初始化,此时为未登录状态,所以被我们之前设置的路由守卫指向到了登录页面,解决这个问题,我们需要在 store 的引入过程中封装一下。

9.解决页面刷新丢失store数据问题

src/utils 目录下创建 cacheStore.js 文件,引入 store,并尝试在 sessionStorage 获取缓存的 store,如果有,则更新 store,并且添加给 window 对象添加 beforeunload 方法,该方法会在页面刷新时触发,将 store.state 存放在 sessionStorage 进行缓存,最后导出 store

,这样,store.state 中的数据会在刷新前进行缓存,并在页面刷新后进行读取合并,达到页面刷新不丢失数据的效果,代码如下:

import store from "@/store";
// 在页面加载时读取sessionStorage里的状态信息
const sessionStore = sessionStorage.getItem("store");
if (sessionStore && sessionStore !== 'undefined') {
  store.replaceState(Object.assign({},
 store.state, JSON.parse(sessionStore)));
  // 如果已经登录,刷新后初始化路由
  if (store.getters.userInfo&&store.getters.userInfo.userId) {
    store.dispatch('permission/handleRoutes')
  }}
//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload", () => {
  sessionStorage.setItem("store", JSON.stringify(store.state));
});
export default store;

main.js 中 store 引入修改如下:

import store from '@/utils/cacheStore'

登录成功后再次尝试刷新页面,发现一切OK了!

10.commit-msg校验添加

项目中,git commit 信息如果不做规范约束,回过头来查看的时候,有时候会一脸茫然,那么关于 git commit 信息的校验怎么做呢?这里我们利用 gitHooks 中的对应钩子做 commit-msg 的校验,package,json 配置如下:

"gitHooks": {
  "commit-msg": "node script/verify-commit-msg.js",
  "pre-commit": "vue-cli-service lint --fix"
}

可以看到,这里还利用了 pre-commit 钩子在 commit 之前做了 lint fix

在 commit-msg 钩子中,执行了 script/verify-commit-msg.js 文件,该文件我照搬了尤大在vue中的校验文件,需要注意的是该校验依赖 yorkie 库,需要 yarn add yorkie -D 安装一下。

具体的校验规范大家可以自行了解一下,这里就不展开讲了,个人常用如下:

feat:新功能(feature)

fix:修补bug

docs:文档(documentation)

style: 格式(不影响代码运行的变动)

refactor:重构(即不是新增功能,也不是修改bug的代码变动)

test:增加测试

chore:构建过程或辅助工具的变动

End

至此,本文就结束了,项目中其他的细节还是需要在项目代码中具体查看,本文只是把主体思路及节点讲述一遍,如有任何问题或建议,欢迎留言讨论!

如果觉得文本不错或者对您有些许帮助,欢迎点赞或者github点个star、follow,十分感谢!