技术栈
- 构建工具 @vue/cli3
- 状态管理:vuex
- 路由:vue-router
- UI 框架 element-ui
- css预处理语言:scss
- 代码规范:eslint
登录
1.登录方式
- 验证码登录
- 扫码登录
2.功能实现
- qrcode获取二维码 get请求生成qrcode(responseType:blob)img标签渲染
- 扫码后轮询调用直到获取user_token 成功登录返回首页
- vuex持久化 利用vuex-persistedstate放入session
- 因项目要求用于长期登录(+判断用户是否已经登录)token存放cookie中
- token验证过期后刷新token(更新vuex,cookie,请求头中的token)
退出登录
- api返回成功后,清空cookie,清空session,跳转登录页
权限
1.登录权限:
手机app扫码成功后返回token,将token存入cookie,并存入vuex 之后在
axios的请求拦截器service.interceptors.request.use中将token放入到请求头中 。http.js
service.interceptors.request.use(
//1.cookie中获取token
//2. 对比cookie中token与vuex中的token,如果不一致证明环境有其他账号登录,清空vuex跳转登录页面
)
service.interceptors.response.use(
//1.token过期刷新后存入header中,同时保存cookie
)
2.页面权限(菜单权限 + 按钮权限):
在
router.beforeEach()中判断权限,无权限直接跳转到404页面。
3.菜单白名单配置:
通过路由的
meta属性给页面添加白名单权限,如果meta设置了当前页面为所有人都可以访问的话,就直接跳转,不判断是否有权限
4.按钮权限:
- 1.每个模块对应有四种权限,查询(get),添加(post),更新(put),删除(delete)
- 2.利用十进制和二进制来表示当前模块所拥有的权限。1111(15),转换后的二进制与权限的关系表示:从右至左数(1代表拥有该权限,0代表不拥有),第一位代表查询,第二位代表添加,第三位代表更新,第四位代表删除。如eg:二进制1111(15),代表用于查询,添加,更新,删除四种权限。
- 3.判断对应模块没有此权限时,移除当前按钮dom元素。
5.接口权限:
最后再加上请求控制作为最后一道防线,路由可能配置失误,按钮可能忘了加权限,这种时候请求控制可以用来兜底,越权请求将在前端被拦截。
项目亮点
- 项目较大,本地分模块加载(一个模块为pages目录下的一个文件夹利用require.context 实现自动注册。) require.context函数接受三个参数
- directory {String} -读取文件的路径
- useSubdirectories {Boolean} -是否遍历文件的子目录
- regExp {RegExp} -匹配文件的正则
语法: require.context(directory, useSubdirectories = false, regExp = /^.//);
借用webpack官网的例子
require.context('./test', false, /.test.js$/);
- 前端首屏菜单点击后生成tab,tab过长显示左右箭头类似el自定义增加标签页触发器(利用keep-alive页面是否缓存)
问题: 页面刷新打开的tab不会消失
原因: 因为存入Vuex中的数据,一刷新页面,就会清空,那么当然找不到当前路由,就进入404 页面了。
解决:
- 一、 可以 将 静态和 动态 构成的完整路由 存放在
sessionStronge / localStronge中,然后页面刷新时,通过在 全局入口文件App.vue的 生命周期 created 中 ,将router = sessionStronge / localStronge存入的完整的路由,页面在刷新时,它会重新加载完整的路由。- 二、如果是使用
Vuex来获取和解析用户菜单的话, 那么你可以在全局入口文件App.vue的 生命周期 created 中 ,再次执行Vuex Action来重新加载用户菜单
- 打包优化
- vuex模块化( namespaced: true//带命名空间)
//1
import { createNamespacedHelpers } from 'vuex'
const { mapState } = createNamespacedHelpers('user')
computed: {
...mapState({
userName: state => state.userName
}
)
}
//2
import { mapState } from 'vuex'
computed: {
...mapState({
userName: state => state.user.userName
}
)
}
- 将vue实例封装为一个app实例并挂载到window上便于全局引用,扩展性强
项目文件配置
- 代理
webpack 打包&项目优化
clean-webpack-plugin:
帮我们清除 打包之后 dist 目录下的其他多余或者无用的代码 因为我们之前可能生成过其他的 代码 如果不清楚的话 可能 多个代码掺杂在一起 容易把我们搞混乱了 clean-webpack-plugin 插件 就是这样由来的 每次生成代码之前 先将 dist 目录 清空。
1.安装
npm i clean-webpack-plugin -D
2.引入
const {CleanWebpackPlugin}=require(‘clean-webpack-plugin’);
之前的版本可能是 直接引入 没有用对象结构这个是我看最新的官网介绍的引入方式
3.使用 在webpack.config.js的plugins 中配置
new CleanWebpackPlugin()
运行 npm run build 就可以看到效果了
webpack build后生成的app、vendor、manifest
- app.js是入口js
- vendor是通过提取公共模块插件来提取的代码块(webpack本身带的模块化代码部分)。
- manifest则是在vendor的基础上,再抽取出要经常变动的部分,比如关于异步加载js模块部分的内容。
抽离第三方模块(webpack.dll.conf.js)
这里我们使用webpack内置的DllPlugin DllReferencePlugin进行抽离
在与webpack配置文件同级目录下新建webpack.dll.config.js
类似于库(element-ui,vue,axios...)在项目中不会经常变更的webpack只需要打包项目本身的文件代码,而不会再去编译第三方库。
// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
// 你想要打包的模块的数组
entry: {
vendor: ['vue','element-ui']
},
output: {
path: path.resolve(__dirname, 'static/js'), // 打包后文件输出的位置
filename: '[name].dll.js',
library: '[name]_library'
// 这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
},
plugins: [
new webpack.DllPlugin({
path: path.resolve(__dirname, '[name]-manifest.json'),
name: '[name]_library',
context: __dirname
})
]
};
在package.json中配置如下命令
"dll": "webpack --config build/webpack.dll.config.js"
接下来在我们的vue.config.js中增加以下代码
configureWebpack: {
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
//对应webpack.dll.config.js生成的json文件路径
manifest: require('./vendor-manifest.json')
}),
new CopyWebpackPlugin([ // 拷贝生成的文件到dist目录 这样每次不必手动去cv
{from: 'static', to:'static'}
]),
//将dll注入html中
new AddAssetHtmlPlugin({
//dll文件位置
filepath: path.resolve(__dirname,"./plublic/vender/*.js"),
//dll引用路径
publicPath:"./vender",
//dll最终输出目录
outputPath:"./vender"
}),
]
};
执行
npm run dll
这样如果我们没有更新第三方依赖包,就不必npm run dll。直接执行npm run dev npm run build的时候会发现我们的打包速度明显有所提升。因为我们已经通过dllPlugin将第三方依赖包抽离出来了。
HappyPack
HappyPack的基本原理是将这部分任务分解到多个子进程中去并行处理,子进程处理完成后把结果发送到主进程中,从而减少总的构建时间
webpack-parallel-uglify-plugin 增强代码压缩
优化代码压缩时间
babel 去除console
babel.config.js 内配置:
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
'env': {
'development': {
'plugins': ['dynamic-import-node']
},
'production': {
'plugins': ['transform-remove-console']
}
}
}
vue.config.js
configureWebpack:{
plugins:[
//将lodash挂载到全局,避免组件内import
new webpack.ProvidePlugin({
_: 'lodash'
})
]
}