Correct posture develop vue background management system

Foreword

Many people believe that when I see the same document are new to vue boring, watching vue, there vueRouter, vuex, vue-cli, es6 (learn not move ...) After reading it for the tutorial and delays to get started the actual project can only write some simple little demo, and this is certainly the actual production work are discrepancies, Ever since I intend to own from scratch using the latest technology stack to build a vue background management system, and so deepen the theoretical knowledge learning and enhance their ability to project, so I hope this series of tutorials to help you develop vue project.

1. Item Basic Introduction

vue-admin-webapp is a admin spa page, which is based vue and element-ui uses the latest distal technology stack, to achieve a login authority authentication, dynamic routing, generating, using easy-mock to simulate the request data, to achieve a typical the business model case, it can help you quickly build back office management system templates, and add routes based on actual business requirements to achieve enterprise-class management page, I believe this project will be able to help you.

- Online Preview -github

- Online Preview -gitee (recommended domestic users)

The current version is based on webpack 4.0+ and vue-cli 3.x version to build, need Node.js 8.9 or later (recommended 8.11.0+), a self-knowledge can find out about the official website

Features

- Login / Logout 
 - Log imitation GeeTest- pole test security policy 
 
- page 
 - for the first time to enter the boot user 
 - sideBar contraction and expansion 
 - full-screen control 
 
- Sidebar 
 - permission to display the corresponding dynamic menu on the left, depending on the user 
 
- rights verification 
 - Administrator page 
 - permissions 
 
- table operation 
 - involving the relevant forms encountered the usual business operations (reference) 
 
- Excel 
 - Excel export 
 - Excel import 
 - export multi-level header 
 
- Echarts 
 - slide show more data 
 - dynamic switching Charts 
 - use the map map 
 
- Icons 
 - Element-icon 
 - Ali iconfont 
 
copy the code

Ready to work

Before you begin, make sure that the installation node and webpack and git locally. Technology stack involved in the project are mainly ES6, vue, vuex, vue-router, vue-cli, axios, webpack, element-ui, easyMock, so you'd better be familiar to advance understanding of this knowledge, you know it will study the project great help

Directory Structure

Here is the directory structure of the entire project

├── public # static resource 
│ ├── favicon.ico # favicon icon 
│ └── index.html # html template 
├── src # source code 
│ ├── api # all requests 
│ ├── assets # Pictures, font and other static resources 
│ ├── components # global common components 
│ ├── layout # overall page layout box 
│ ├── mixins # global mixing module 
│ ├── plugins # global plugins section 
│ ├── router # routing 
│ ├ ── store # global store management 
│ ├── style # global style 
│ ├── utils # global public methods 
│ ├── vendor # public vendor (excel import and export) 
│ ├── views # views of all pages 
│ ├── App.vue # entry page 
│ ├── main.js # entry file loading component initialization 
├── .borwserslistrc # browser compatibility related 
├── .env.xxx # environment variable configuration  
├── .eslintrc.js # eslint configuration item  
├── .gitignore.js # git ignore file settings
├── .babelrc.config.js # babel-loader configuration 
├── package.json # package.json 
├── postcss.config.js # postcss arranged 
└── vue.config.js # vue-cli configuration 
duplicated code

installation

Item # clone 
git clone [email protected]: gcddblue / VUE-ADMIN-webapp.git 
# into the project directory 
cd VUE-ADMIN-the webapp 
# installation depends 
npm install 
# start the service 
npm run serve 
copy the code

After startup is complete open the browser to access http: // localhost: 8080, then you can according to their actual needs, you can add or modify the route, write your own business code.

2. Page Architecture

Correct posture develop vue background management system


Remove outer login page, the entire page architecture consists of three parts of the head to the right sidebar content page encapsulate these three components of the project @ / layout / index.js document composition, to switch to the right by clicking on the left-hand menu router-view route change, the project file corresponding to the following

Correct posture develop vue background management system


3.axios package

In vue project, and background interact with this request, we usually choose axios library, which is based on the promise of http library, you can run in the browser and node.js in. In this project, the main achievement of the request and response intercept, get, post request package.

Configure different environments

Correct posture develop vue background management system


) By creating a file in different environments in the project, I've just created a development and production environment, of course, you can also create other documents based on tests .env.test to .env.production example:

ENV = 'production'
# base api
VUE_APP_BASE_API = 'https://www.easy-mock.com/mock/5cee951f11690b5261b75566/admin'
复制代码

只要以 VUE_APP_ 开头的变量都会被 webpack.DefinePlugin 静态嵌入到客户端的包中。你可以在应用的代码中这样访问它们,例如我在@/api/index.js中初始化axios:

const $axios = axios.create({
 timeout: 30000,
 // 基础url,会在请求url中自动添加前置链接
 baseURL: process.env.VUE_APP_BASE_API
})
复制代码

通过创建api文件夹将所有接口都集中在这个文件夹中,根据不同的业务创建不同js文件,来更好的划分接口的功能,其中index.js中代码如下:

import axios from 'axios'
import Qs from 'qs' // 处理post请求数据格式
import store from '@/store'
import router from '@/router'
import Vue from 'vue'
import { Loading, Message } from 'element-ui' // 引用element-ui的加载和消息提示组件
const $axios = axios.create({
 // 设置超时时间
 timeout: 30000,
 // 基础url,会在请求url中自动添加前置链接
 baseURL: process.env.VUE_APP_BASE_API
})
Vue.prototype.$http = axios // 这里并发请求以便在组件使用this.$http.all(),具体看dashborad页面
// 在全局请求和响应拦截器中添加请求状态
let loading = null
/**
 * 请求拦截器
 * 用于处理请求前添加loading、判断是否已保存token,并在每次请求头部添加token
 */
$axios.interceptors.request.use(
 config => {
 loading = Loading.service({ text: '拼命加载中' })
 const token = store.getters.token
 if (token) {
 config.headers.Authorization = token // 请求头部添加token
 }
 return config
 },
 error => {
 return Promise.reject(error)
 }
)
/**
 * 响应拦截器
 * 用于处理loading状态关闭、请求成功回调、响应错误处理
 */
$axios.interceptors.response.use(
 response => {
 if (loading) {
 loading.close()
 }
 const code = response.status
 // 请求成功返回response.data
 if ((code >= 200 && code < 300) || code === 304) {
 return Promise.resolve(response.data)
 } else {
 return Promise.reject(response)
 }
 },
 error => {
 if (loading) {
 loading.close()
 }
 console.log(error)
 if (error.response) {
 switch (error.response.status) {
 case 401:
 // 返回401 清除token信息并跳转到登陆页面
 store.commit('DEL_TOKEN')
 router.replace({
 path: '/login',
 query: {
 redirect: router.currentRoute.fullPath
 }
 })
 break
 case 404:
 Message.error('网络请求不存在')
 break
 default:
 Message.error(error.response.data.message)
 }
 } else {
 // 请求超时或者网络有问题
 if (error.message.includes('timeout')) {
 Message.error('请求超时!请检查网络是否正常')
 } else {
 Message.error('请求失败,请检查网络是否已连接')
 }
 }
 return Promise.reject(error)
 }
)
// get,post请求方法
export default {
 post(url, data) {
 return $axios({
 method: 'post',
 url,
 data: Qs.stringify(data),
 headers: {
 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
 }
 })
 },
 get(url, params) {
 return $axios({
 method: 'get',
 url,
 params
 })
 }
}
复制代码

如上,大家可以看我的注释说明,axios配置的封装是整个项目中很重要的模块,其实在不同的项目中,axios封装都大同小异,所以,只要掌握了一种技巧,下次开发新项目也就很容易完成封装这块。

4.权限验证及侧边栏

路由

路由是组织一个vue项目的关键,在对项目原型分析后,接下来的第一步就是编写路由,本项目中,主要分为两种路由,currencyRoutes 和 asyncRoutes

currencyRoutes:代表通用路由,意思就是不需要权限判断,不同角色用户都显示的页面,如:登陆页、404等

asyncRoutes: 代表动态路由,需要通过判断权限动态分配的页面,有关的权限判断的方法接下来会介绍。

路由相关配置说明:

/**
 * 路由相关属性说明
 * hidden: 当设置hidden为true时,意思不在sideBars侧边栏中显示
 * mete{
 * title: xxx, 设置sideBars侧边栏名称
 * icon: xxx, 设置ideBars侧边栏图标
 * noCache: true 当设置为true时不缓存该路由页面
 * }
 */
复制代码

权限验证动态添加侧边栏

本项目通过路由联动更新侧边栏,所有侧边栏配置都是在前端完成的,通过访问接口,后端会返回一个权限相关的list数组,其中数组值为路由的name属性值,前端通过递归遍历asyncRoutes判断权限list中是否包含有对应的name路由,最终会返回包含该用户角色所有权限路由页面的addRoutes的数组对象。

具体实现是在路由index.js中设置一个全局前置导航守卫,具体判断流程如下:

Correct posture develop vue background management system


// 导航守卫
router.beforeEach(async (to, from, next) => {
 document.title = getTitle(to.meta.title)
 if (to.path === '/login') {
 next()
 } else {
 if (store.getters.token) {
 const hasRoles = store.getters.roles.length > 0
 if (hasRoles) {
 next()
 } else {
 try {
 const { roles } = await store.dispatch('user/_getInfo')
 const addRoutes = await store.dispatch(
 'permission/getAsyncRoutes',
 roles
 )
 router.addRoutes(addRoutes)
 // hack method to ensure that addRoutes is complete
 // set the replace: true, so the navigation will not leave a history record
 next({ ...to, replace: true })
 } catch (error) {
 Message.error(error)
 }
 }
 } else {
 next({
 path: '/login',
 query: {
 redirect: to.fullPath
 }
 })
 }
 }
})
复制代码

这里我在通过addRoutes添加路由时,遇到一个bug,当切换角色时,并不能删除之前添加动态路由,所以这边重新初始化router.matcher的属性方式实现:

const creatRouter = () => {
 return new Router({
 routes: currencyRoutes,
 scrollBehavior() {
 return { x: 0, y: 0 }
 }
 })
}
const router = creatRouter()
// 解决addRoute不能删除动态路由问题
export function resetRouter() {
 const reset = creatRouter()
 router.matcher = reset.matcher
}
复制代码

当我每次退出登录的时候执行resetRouter方法来初始化router对象,实现删除之前动态添加的路由。

最后通过element-ui的el-menu组件来递归遍历路由对象加载侧边栏。

5.Mock数据

身为前端开发人员,相信大家都知道Mock数据吧,它的作用主要就是伪造假数据使团队可以并行开发,本项目使用了 easy-mock 来实现接口数据的请求,大家可以去官网看下简单教程,easy-mock 它的好处就是不用像传统mock数据那样需要在项目中创建mock文件夹并拦截ajax来实现假数据请求,它是真真实实的api请求,并允许任何跨域请求,下面是本项目所有接口

Correct posture develop vue background management system


其中所有接口通过创建 _res 字段来判断请求是否含有Authorzation头部字段是否含有token来判断用户是否是登陆状态,如下 getCardsData接口的配置:

{
 code: 0,
 data: {
 vistors: '@integer(10000, 100000)',
 message: '@integer(100, 1000)',
 order: '@integer(0, 1000)',
 profit: '@integer(1000, 100000)'
 },
 _res: function({
 _req,
 Mock
 }) {
 if (!_req.header.authorization) {
 return {
 status: 401,
 data: {
 msg: '未授权'
 }
 }
 } else {
 return {
 status: 200
 }
 }
 }
}
复制代码

mock数据在项目开发中能够起到推进项目进度的功效,大家可以预先和后端人员商量好,并先拿到假数据字段,然后mock自己的假数据,这样你就可以不用等后端人员开发接口而使项目卡住。一般在项目中,创建.env.development 和.env.production 文件,代表了开发和生产环境,在文件里可以定义不同环境接口的请求url

# base api
VUE_APP_BASE_API = 'https://www.easy-mock.com/mock/5cee951f11690b5261b75566/admin'
复制代码

在封装axios这样初始化

const $axios = axios.create({
 // 设置超时时间
 timeout: 30000,
 // 基础url,会在请求url中自动添加前置链接
 baseURL: process.env.VUE_APP_BASE_API
})
复制代码

这样就可以自动根据不同的环境切换请求地址,不用我们一个一个的修改每一个请求接口

6.登录

Correct posture develop vue background management system


通过将登录函数封装在store中,当点击登陆时,调用this.$store.dispatch('user/_login', this.ruleForm) 这个action方法,当后台接口验证成功时,会返回 token 字段,前端会调用 localStroage 接口将这个 token 保存在本地,以后每次请求前通过拦截器将这个token保存在 Authorization 这个头部字段中,后台只要验证这个token就知道这个用户的信息了。还不只token的同学,可以 疯狂点击token说明 里面对http为什么要添加toekn及token介绍的都很详细。

这里我还采用了仿 geetest 行为验证,通过滑动图片来验证真人操作,其中原理利用 h5 canves绘制功能,绘制底部图片和滑块图片,然后监听mouseMove事件,当滑动block抠出的图片和初始化图片的y坐标差小于10时触发验证成功函数。

7、优化及小技巧

巧用Mixins

如果你的多个组件都用到一个或多个方法,我们可以不用每次都粘贴复制,这样岂不是很low,我们可以将这些方法封装在一个js文件中,当我的某个组件需要调用这个方法时

import aMixin from '@/mixins/a-mixin'
export default {
 name: 'page1',
 mixins: [newsMixin] //调用mixins属性,将aMixin这个模块的数据及方法等都添加进这个组建吧
}
复制代码

mixins的使用使用规则

Object.freeze方法

这个方法有什么用呢,它主要是可以将一个对象冻结,防止对象被修改,那这个对vue项目有什么优化作用呢,大家都知道vue采用了数据劫持的方式遍历数据对象,把这些属性转为getter、settter方法来监听并通知数据的变化,所以当你遇到一个巨大的数组或者对象,并且确定数据不会修改,这时就可以使用 Object.freeze() 方法来组织vue对这个巨大数据的转化,,这可以让性能得到很大的提升,举个例子:

new Vue({
 data: {
 // vue不会对list里的object做getter、setter绑定
 list: Object.freeze([
 { value: 1 },
 { value: 2 }
 ])
 },
 mounted () {
 // 界面不会有响应
 this.list[0].value = 100;
 // 下面两种做法,界面都会响应
 this.list = [
 { value: 100 },
 { value: 200 }
 ];
 this.list = Object.freeze([
 { value: 100 },
 { value: 200 }
 ]);
 }
})
复制代码

自动化导入模块

当我们某个组件或js文件需要引入多个模块时,一般做法就是,import每个模块,这样显然是相当繁琐的,这时 require.context 函数将派上用场,那个这个函数到底怎么用呢,这里官法介绍是 主要用来实现自动化导入模块,在前端工程中,如果遇到从一个文件夹引入很多模块的情况,可以使用这个api,它会遍历文件夹中的指定文件,然后自动导入,使得不需要每次显式的调用import导入模块

require.context 函数接受三个参数:

  1. directory {String} -读取文件的路径

  2. useSubdirectories {Boolean} -是否遍历文件的子目录

  3. gExp {RegExp} -匹配文件的正则

require.context('./test', false, /.test.js$/)
#上面的代码遍历当前目录下的test文件夹的所有.test.js结尾的文件,不遍历子目录
复制代码

require.context 函数执行后返回一个函数,并且这个函数包含了三个属性:

  1. resolve {Function} -接受一个参数request,request为test文件夹下面匹配文件的相对路径,返回这个匹配文件相对于整个工程的相对路径

  2. keys {Function} -返回匹配成功模块的名字组成的数组

  3. id {String} -执行环境的id,返回的是一个字符串

我们常会遍历keys返回的数组来对路径进行处理,这是相当方便的,最后 require.context 返回的函数接受keys放回数组中的路径成员作为参数,并返回这个路径文件的模块

下面是我使用 require.context 函数动态生成moudles对象

Correct posture develop vue background management system


import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
const path = require('path')
Vue.use(Vuex)
const files = require.context('./modules', false, /\.js$/)
let modules = {}
files.keys().forEach(key => {
 let name = path.basename(key, '.js')
 modules[name] = files(key).default || files(key)
})
const store = new Vuex.Store({
 modules,
 getters
})
export default store
复制代码

cdn引入

对于一些不常改动的模块库,例如: vue vueRouter vuex echarts element-ui 等, 我们让 webpack 不将他们进行打包,而是通过 cdn 引入,这样就可以减少代码大小,减少服务器带宽,并通过cdn将它们缓存起来,提高网站性能 。

具体实现就是修改 vue.config.js ,为对象模块添加 externals 完整配置如下:

const cdn = {
 css: [
 // element-ui css
 'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
 ],
 js: [
 // vue
 'https://unpkg.com/vue/2.5.22/vue.min.js',
 // element-ui
 'https://unpkg.com/element-ui/lib/index.js',
 // vue
 'https://unpkg.com/vuex/3.1.0/vuex.min.js'
 ]
}
# 不打包vue、element-ui、vuex
module.exports = {
 externals: {
 vue: 'Vue',
  'element-ui':'ELEMENT',
  vuex: 'Vuex'
 },
 chainWebpack: config => {
  config.plugin('html')
 .tap(args => {
 args[0].cdn = cdn
 return args
 })
 }
}
复制代码

接下来修改 index.html

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width,initial-scale=1.0">
 <link rel="icon" href="<%= BASE_URL %>favicon.ico">
 <% if (process.env.NODE_ENV === 'production') { %>
  <!-- 引入样式 -->
 <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
 <link rel="stylesheet" href="<%=css%>">
 <% } %>
 <!-- 引入js -->
 <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
 <script src="<%=js%>"></script>
 <% } %> 
 <% } %>
 <title>vue-admin-webapp</title>
 </head>
 <body>
 <noscript>
 <strong>We're sorry but vue-admin-webapp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
 </noscript>
 <div id="app"></div>
 <!-- built files will be auto injected -->
 </body>
</html>
复制代码

Well, the big announcement to

vue cli3 multi-page configuration

I can focus on another article using the correct posture multi-page project vue cli3 configuration

vue cli3 project initialization

I can focus on another article to create a project using the correct posture vue cli3

to sum up

This project is my work apart from intermittent development, wrote not too technical paste, writing ability and logical organization is still quite poor, forgive me. Before the start at first did not think we should do quite well, and did not realize the real step by step, and his original vision is still discrepancies, met a lot of bug period, mostly due to not pay attention to the details, let me more experience  a good memory as bad written  words, practice is the truth ah, more hands-on, multi-exploration

Correct posture develop vue background management system


Guess you like

Origin blog.51cto.com/14516511/2434507