一、准备工作
0. 给el-container设置最小宽度,防止挤压变形
0. 给目录配置别名
// vue.config.js文件中
const path = require('path')
// 处理路径函数
function resolve (dir) {
console.log(__dirname)
return path.join(__dirname, dir)
}
module.exports = {
lintOnSave: true, // 启用eslint
// 解决[WDS] Disconnected! 报错
devServer: {
headers: {
'Access-Control-Allow-Origin': '*'
},
hotOnly: true,
disableHostCheck: true
},
// 打包时去console插件
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
}
},
// 配置别名
chainWebpack (config) {
config.resolve.alias.set('views',resolve('src/views')).set('@', resolve('src'))
}
}
1. 登录逻辑以及token
1. 前端输入用户名密码进行登录
2. 后端服务器验证登录成功,会生成一个token字段,返回给前端
3. 前端将token存储在sessionStorage中
4. 以后的每次请求都要携带此token
2. API接口授权
// 利用axios请求拦截器
axios.interceptors.request.use(config=>{
//为请求头对象,添加token验证的Authorization字段
config.headers.Authorization = window.sessionStorage.getItem("token")
return config
})
3. 解决左侧菜单刷新后默认高亮
-
方法一:
sessionStorage保存每次点击子菜单选项绑定的唯一index , 刷新以后created里面同步到data中定义的activePath ,el-menu的default-active绑定此activePath 注意:不能是mounted生命周期中同步,具体见各个生命周期会进行的事件
https://zhuanlan.zhihu.com/p/71958016
vue生命周期图解
-
方法二:el-menu的default-active直接绑定 $route.path
二、用户管理
4. 栅格布局
5. Table设置索引列
<!-- 设置索引列 -->
<el-table-column
label="#"
type="index"
width="60"
align="center"
>
</el-table-column>
6. 作用域插槽实现switch开关状态
7. trycatch用法
8. 表单绑定以及验证
1. 先data中定义表单数据formData ,表单校验规则formRules 。 对象里有多个属性
2. 不光 el-input 要利用v-model绑定到formData的各个属性上
3. el-form也要用 :model 绑定到表单数据formData上
4. el-form-item 还要用 prop绑定formRules里的具体对应的校验规则,属性值可以是数组,里面包含多个规则(见9中的 addUserFormRules)
9. 邮箱和手机号自定义校验规则
1. 先在data中定义利用回调函数自定义校验规则,注意不是在return中
2. 再在prop绑定的校验规则中用validator指向定义的该回调,trigger:blur失焦时候触发
// 定义在data中的回调
// 验证邮箱的规则
var checkEmail = (rule, value, cb) => {
// 验证邮箱的正则表达式
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
if (regEmail.test(value)) {
// 合法的邮箱
return cb();
}
cb(new Error("请输入合法的邮箱"));
};
// 验证手机号的规则
var checkMobile = (rule, value, cb) => {
// 验证手机号的正则表达式
const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;
if (regMobile.test(value)) {
return cb();
}
cb(new Error("请输入合法的手机号"));
};
// 定义在data中的校验规则
// 添加表单的验证规则对象
addUserFormRules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{
min: 3,
max: 10,
message: "用户名的长度在3~10个字符之间",
trigger: "blur"
}
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{
min: 6,
max: 15,
message: "用户名的长度在6~15个字符之间",
trigger: "blur"
}
],
email: [
{ required: true, message: "请输入邮箱", trigger: "blur" },
{ validator: checkEmail, trigger: "blur" }
],
mobile: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{ validator: checkMobile, trigger: "blur" }
]
}
10. 表单提交之前要做预校验
// el-form-item 要绑定prop的验证规则字段,用v-model绑定到输入框的值 ,el-form还要用 :rule 绑定到验证规则 , 用 :model 绑定到表单数据
11. 侧边el-aside底部出现滚动条
将el-aside的宽度设置小于200px , 在点击aside内部的导航栏时,底部出现横向滚动条。
经过简单测试,宽度>=200px的时候不会有
解决办法:在el-aside的内部el-menu的外部套一个el-scrollbar组件,在style属性中设置width:100% 。 类似情形如果出现纵向滚动,就设为高度100%
12. 列表分页的问题
12-1. 刷新以后分页的当前页码和每页条数被重置
思路:
1. pagination组件的current-page和page-size 绑定data中定义的初始值pagenum和pagesize
2. 点击更改页码或者容量时,回掉函数内部把当前的pagesize和pagenum同步到sessionStorage中
3. created生命周期里重新获取并赋值给初始值 , 再请求列表数据
注意: current-page和page-size要绑定的是Number类型 , 要利用parseInt()转换类型
created() {
if (window.sessionStorage.getItem("currentPage")) {
this.params.pagenum = parseInt(
window.sessionStorage.getItem("currentPage")
);
}
if (window.sessionStorage.getItem("currentPageSize")) {
this.params.pagesize = parseInt(
window.sessionStorage.getItem("currentPageSize")
);
}
this.getUsers();
}
12-2. 分页中删除最后一页数据自动跳到上一页
// 解决分页删除当前页不跳转,先判断当前应该处于的页数 , 再给pagenum重新赋值
// 因为usersTotal总数需要在重新请求后才能同步最新数据,所以这里计算需要手动减1
let totalPage = Math.ceil((this.usersTotal - 1) / this.params.pagesize);
let currentPage = this.params.pagenum > totalPage ? totalPage : this.params.pagenum;
this.params.pagenum = currentPage < 1 ? 1 : currentPage;
// 同步sessionStorage中的currentPage
window.sessionStorage.setItem("currentPage", currentPage);
// 分页器的代码如下:
<el-pagination
:background="true"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="params.pagenum"
:page-sizes="[2, 3, 4, 5]"
:page-size="params.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="usersTotal"
>
</el-pagination>
// usersTotal是data中定义的用户总数 , params是用户请求的参数
params: {
pagesize: 4,
pagenum: 1,
query: "" // 用户搜索关键字 , 绑定到搜索输入框
},
12-3. 删除最后一页数据再刷新显示列表数据为空
因为删除最后一页时候,没有同步sessionStorage中的currentPage,所以再刷新请求利用的还是最后一页的currentPage值,故请求的仍是原尾页的数据,为空
window.sessionStorage.setItem("currentPage", currentPage);
三、权限管理
13. 作用域插槽显示不同等级的标签
<el-table-column prop="level" label="权限等级" align="center">
<template slot-scope="level">
<el-tag v-if="level.row.level === '0'" type="success">等级一</el-tag>
<el-tag v-else-if="level.row.level === '1'" type="warning">等级二</el-tag>
<el-tag v-else type="danger">等级三</el-tag>
</template>
</el-table-column>
另外思路: 可能还可以用过滤器filters配合switch实现(???)暂时没试过
14. 删除权限标签视图刷新以后展开的权限列表又关闭了
15. 利用递归获取当前角色的所有三级权限id , el-tree默认选中
// 递归获取已有三级权限的id
getDefaultKeys(data, arr) {
/*
思路:1. 点击分配权限,传递当前role的数据,获取当前角色的所有已有三级权限id , 组成数组 , 赋值给defaultExpandedArray
2. 遍历roleData, 判断当前数据是否有children , 没有就把当前对象的id push到数组
3. 有就遍历该children数组 , 然后对每一项元素继续调用this.getDefaultKeys() 进行判断
*/
if (!data.children) {
arr.push(data.id);
return false;
} else {
data.children.forEach(i => this.getDefaultKeys(i, arr));
}
},
16. 给上一个角色分配权限,再点下一个角色,默认选中了上一个角色有的权限
// 在关闭对话框时候,要把默认选中的权限 defaultCheckedKeysArray数据清空,不然点击下一个角色的分配权限,会默认选中上一个角色的权限
// 关闭el-tree分配权限对话框
closeSetRightsDialog() {
/* 在关闭对话框时候,要把默认选中的权限 defaultCheckedKeysArray数据清空
不然点击下一个角色的分配权限,会默认选中上一个角色的权限
*/
this.defaultCheckedKeysArray = [];
}
17. vue-table-with-tree-grid实现树形table表格
vue-table-with-tree-grid
四、商品管理
18. moment.js格式化时间
-
先定义全局或者局部过滤器
import moment from 'moment' // 定义全局的时间过滤器 Vue.filter('dateFilter', (time) => { return moment(time).format('YYYY-MM-DD HH:mm:ss') // 格式:1970-01-18 20:39:05 })
-
引用
<el-table-column header-align="center" align="center" width="250" label="创建时间"> <template slot-scope="{row}"> {{ row.add_time | dateFilter }} </template> </el-table-column>
19. el-tab标签栏和el-steps步骤条联动
https://i.postimg.cc/xTxK7ZMy/Screenshot-2.png
20. el-tab和el-form的层级关系
21. 利用before-leave在切换tab标签之前做判断
1. 要判断当前步骤是不是由 1 到 2
2. this.queryInfo.goods_cat.length !== 3 时 返回 false
22. upload图片上传,发请求显示无效token
// 说明upload上传没用的axios发请求
// 利用headers属性,设置请求头
uploadUrl: 'http://127.0.0.1:8888/api/private/v1/upload', // 图片上传服务器地址
headerObj: {
// upload设置请求头
Authorization: window.sessionStorage.getItem('token')
}
23. 图片上传成功,但是缩略图不能正常显示,是白色方块
// 因为el-upload中:file-list绑定了提交的表单信息里的pics , 导致每次pics数组里push的对象如下:
[{"pic":"tmp_uploads\\6dc05d2211b648cefe5d4e593c952f8e.jpeg","uid":1618827444464,"status":"success"}]
// 正常应该是只有pic属性
24. vue-quill-editor富文本编辑器使用
25. lodash的_.cloneDeep深拷贝
五. 数据统计
1. e-charts的使用
- 在mounted生命周期中初始化
六. 项目优化上线
blog.csdn.net/weixin_4438…
1. 顶部进度条效果 nprogress.js
- 在main.js中利用axios拦截器实现
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'
// 请求拦截器中显示进度条效果
axios.interceptors.request.use(config => {
Nprogress.start()
// 为请求头对象,添加token验证的Authorization字段
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
// 响应拦截器中停止进度条效果
axios.interceptors.response.use(config => {
Nprogress.done()
return config
})
- 利用路有守卫实现
router.beforeEach((to, from, next) => {
if (to.path == '/login') {
sessionStorage.removeItem('username');
}
let user = sessionStorage.getItem('username');
if (!user && to.path != '/login') {
next({path: '/login'})
} else {
NProgress.start();
next()
}
});
router.afterEach(transition => {
NProgress.done();
});
2. build期间去掉所有的console
babel-plugin-transform-remove-console 插件
// 注意需要只在生产阶段去console 要先做环境的判断 process.env.NODE_ENV === 'production'
3. 生成打包报告
4. 为开发模式和发布模式指定不同的打包入口
// main.js复制两份分别命名main-dev.js / main.prod.js
// vue.config.js中使用chainWebpack
module.exports = {
// 利用when判断环境,指定不同的打包入口文件
// 发布模式
config.when(process.env.NODE_ENV === 'production', config => {
// entry找到默认的打包入口,调用clear则是删除默认的打包入口
// add添加新的打包入口
config.entry('app').clear().add('./src/main-prod.js')
})
// 开发模式
config.when(process.env.NODE_ENV === 'development', config => {
config.entry('app').clear().add('./src/main-dev.js')
})
}
5. 通过externals加载外部的CDN资源
-
配置如下 :
6. 优化打包element-ui
7. 自定义首页标题内容
8. 路由懒加载
-
使用babel的话,先安装@babel/plugin-syntax-dynamic-import
-
babel.config.js中声明一下插件
-
路由中改造组件导入方式
9. 开启gzip压缩
一般是后端的范围 , 需要服务器是node写的,可能需要前端做
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!