1. vue动态路由导航栏菜单
后台管理系统中,根据不同的权限显示不同的导航栏菜单
基本流程:首先获取数据--->动态拼接路由信息--->动态添加路由信息
# router/index.js
import store from '@/store'
const routes = [
{
path:'/',
redirect:'/login'
},
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue')
},
{
path: '/main',
name: 'Main',
component: () => import('../views/Main.vue'),
redirect:'/welcome', // 重定向到 /welcome
children:[{
path:'/welcome',
name:'Welcome',
component: () => import('../views/Welcome.vue')
}]
}
]
// 获取数据,为了减少请求的发送我们可以把数据存储到vuex
function add() {
let arr = []
// store.state.menus存储在vuex里面的数据
store.state.menus.forEach(item=>{
item.children.forEach(v=>{
arr.push({
path: '/' + v.path,
name: v.path,
component: () => import('../views/' + v.path + '/' + v.path + '.vue')
})
})
})
return arr
}
添加动态路由(addRoute)
router.addRoute() // 添加顶级路由对象
router.addRoute('Main',...add()) // 添加二级路由对象
在Vue Router里面有动态添加路由addRoute方法
设置NotFound页面
对于那些没有匹配到的路由,我们通常会匹配到固定的某个页面,进行报错提醒。
可以编写一个动态路由用于匹配所有的页面
{
path:'/:pathMatch(.*)',
component:()=>import('../views/NotFound.vue')
}
NotFound.vue页面
<div class='not'>
<h2>Page Not Found</h2>
<p>你打开的页面不存在</p>
你输入的是:{{$route.params.pathMatch}}
</div>
这里还有另一种写法:
注意:只是在/:pathMatch(.*)
后面加了*
{
path:'/:pathMatch(.*)*',
component:()=>import('../views/not.vue')
}
这两种写法的区别在于是否解析/
2. 改变element-ui中MessageBox弹框(确认消息)
官网给我们代码:
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
为了解决回调地狱,我们将其改编成async/await形式:
注意:await只接受then()语句的返回,所以catch不能去掉
const confirmReturn = await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err=>err)
// 点击确定 返回值:confirm
// 点击取消 返回值:cancel
if(confirmReturn != 'confirm') return this.$message.info('已取消删除')
3. 树形表格(table_tree)
1. 下载插件
cnpm i vue-table-with-tree-grid -S
2. 全局注册树形表格
import TreeTable from 'vue-table-with-tree-grid'
Vue.component('tree-table',TreeTable)
3. 使用
data
:绑定一个数组(具有树形结构)
columns
:[{label:‘分类名称’,prop:‘cat_name’},{label:‘是否有效’,type:‘template’,template:‘isok’}]自定义模板
selection-type
:是否显示勾选框
expand-type
:是否显示展开
show-index
:显示index 和 index-text="#" 一起使用
show-row-hover
:鼠标滑过有高亮显示
border
:纵向边框
<tree-table
:data="catelist"
:columns="columns"
:selection-type="false"
:expand-type="false"
show-index
index-text="索引"
:show-row-hover="false"
border
>
<!-- 是否有效 -->
<template slot="isOk" slot-scope="scope">
<i v-if="!scope.row.cat_deleted" class="el-icon-success" style="color:lightgreen"></i>
<i v-else class="el-icon-error" style="color:red"></i>
</template>
<!-- 排序 -->
<template slot="sort" slot-scope="scope">
<el-tag v-if="scope.row.cat_level === 0" size="mini">一级</el-tag>
<el-tag v-if="scope.row.cat_level === 1" size="mini" type="success">二级</el-tag>
<el-tag v-if="scope.row.cat_level === 2" size="mini" type="warning">三级</el-tag>
</template>
</tree-table>
对于columns的配置:
columns:[{
label:'分类名称',
prop:'cat_name'
},{
label:'是否有效',
type:'template',
template:'isOk'
},{
label:'排序',
type:'template',
template:'sort'
}]
4. vue跳转路由 加载进度条
1. 下载插件
npm install --save nprogress
2. main.js引入:导入NProgress, 包对应的JS和CSS
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
3. 使用
和路由守卫一起使用:
//在页面跳转使用
router.beforeEach((to,from,next) => {
//开始进度条
NProgress.start();
// 继续路由
next();
});
router.afterEach((to,from,next) => {
//结束进度条
NProgress.done();
});
也可以写在axios拦截器里面:
axios.interceptors.request.use(config => {
//当进入request拦截器,表示发送了请求,我们就开启进度条
NProgress.start()
return config
})
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(res=>{
//当进入response拦截器,表示请求已经结束,我们就结束进度条
NProgress.done()
return res
})
4. 修改进度条样式
#nprogress .bar {
background: red !important;
}
5. 利用element-ui组件(Upload
)上传图片
注意:图片上传不会走我们封装的axios,它是一个独立的系统,所以我们要自己定义请求路径和请求头信息
action:上传的地址
headers:设置上传的请求头部
on-preview:点击文件列表已上传的文件时钩子,进行图片预览
on-remove:文件列表移除文件时的钩子
on-success:文件上传成功时的钩子
list-type:文件列表的类型
<el-upload
class="upload-demo"
action="http://127.0.0.1:8888/api/private/v1/upload"
:headers="headersObj"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:on-success="handlerSuccess">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
<!-- 图片预览弹出框 -->
<el-dialog
title="图片预览"
:visible.sync="dialogVisible"
width="50%">
<img :src="previewSrc" alt="" class="previewimg">
</el-dialog>
<script>
export default {
data() {
return {
headersObj:{
Authorization:sessionStorage.getItem('token')
},
dialogVisible:false,
previewSrc:'',
pics:[]
}
},
methods: {
// 图片预览
handlePreview(file) {
this.previewSrc = file.response.data.url
this.dialogVisible = true
},
// 图片移除
handleRemove(file) {
const filePath = file.response.data.tmp_path
const i = this.pics.findIndex(x => x.pic == filePath)
this.pics.splice(i,1)
},
// 图片上传成功
handlerSuccess(response) {
// tmp_path图片在服务器的路径
const picInfo = { pic: response.data.tmp_path }
this.pics.push(picInfo)
}
}
}
</script>
<style lang='scss' scoped>
.previewimg {
width: 100%;
}
</style>
可通过设置limit
和on-exceed
来限制上传文件的个数和定义超出限制时的行为
multiple 可以一次选择多个图片上传
<el-upload
multiple
:limit="3"
:on-exceed="handleExceed">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
methods:{
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件`);
},
}
通过设置before-remove
来阻止文件移除操作
预删除
before-remove:删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false,停止删除
<el-upload
:before-remove="beforeRemove">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
methods:{
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }?`);
}
}
使用 before-upload
限制用户上传的图片格式和大小
before-upload:上传文件之前的钩子,参数为上传的文件,若返回false则停止上传
<el-upload
:before-upload="beforeAvatarUpload">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过2MB</div>
</el-upload>
methods:{
beforeAvatarUpload(file) {
const imageType = ['image/jpeg','image/png']
const isJPG = imageType.includes(file.type)
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG/PNG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
}
}
drag
拖拽上传
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
6. vue-quill-editor
富文本编译器
1. 下载插件
npm install vue-quill-editor -S
2. 在main.js引入
// 导入富文本编辑器
import VueQuillEditor from 'vue-quill-editor'
// 导入富文本编辑器样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 全局注册富文本编辑器
Vue.use(VueQuillEditor)
3. 使用
<quill-editor
v-model="content"
:options="editorOption"
// 可以绑定事件
@blur="onEditorBlur($event)" // 失去焦点事件
@focus="onEditorFocus($event)" // 获取焦点事件
@change="onEditorChange($event)"// 内容改变事件
></quill-editor>
options:是用来对这个富文本编辑器进行设置的。
工具栏是分块的,默认显示的比较多,且有重复功能的,可以在editorOption的modules属性中设置,只显示自己需要的。还可以设置placeholder属性设置输入框中的提示词。
editorOption:{
// placeholder设置提示词
placeholder: '请输入正文......',
// modules设置工具栏
modules: {
toolbar: [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
['formula'],
['clean'],
['link', 'image', 'video'],
[{ 'header': 1 }, { 'header': 2 }],
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
[{ 'script': 'sub'}, { 'script': 'super' }],
[{ 'indent': '-1'}, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'size': ['small', false, 'large', 'huge'] }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
[{ 'align': [] }]
]
}
}
7. 项目中使用lodash
1. 下载插件
cnpm i lodash -S
2. 导入
// 引入lodash库(官方推荐将lodash导入为_)
import _ from 'lodash'
简单说几个常用的方法,了解更多可以去lodash官网地址
_.clone(value)
:创建一个 value 的浅拷贝
_.cloneDeep(value)
:创建一个value的深拷贝
_.assign(object, [sources])
分配来源对象的可枚举属性到目标对象上。 来源对象的应用规则是从左到右,随后的下一个对象的属性会
覆盖
上一个对象的属性
_.merge(object, [sources])
该方法类似_.assign, 除了它
递归合并
sources 来源对象自身和继承的可枚举属性到 object 目标对象。
3. 使用
addGoods() {
// 验证
this.$refs.addForm.validate(async (valid) => {
if(!valid) return this.$message.error('请填写必要的表单项!')
// this.addForm.goods_cat = this.addForm.goods_cat.join(',')
// 以上写法不正确:级联选择器绑定的要是一个数组(会改变原来的数据)
// 第一种写法:深拷贝
let copyForm = JSON.parse(JSON.stringify(this.addForm))
// 第二种写法:借助lodash的cloneDeep深拷贝方法
let copyForm = _.cloneDeep(this.addForm)
// 然后再处理goods_cat字段
copyForm.goods_cat = copyForm.goods_cat.join(',')
});
}
let data1 = {
name:'uu盘',
arr:{
flag:false
}
}
let data2 = {
name:'你好',
arr:[{id:1,bool:false},{id:2,bool:true}]
}
let obj = Object.assign(data2,data1)
console.log(obj);
let data1 = {
name:'uu盘',
arr:{
flag:false
}
}
let data2 = {
name:'你好',
arr:[{id:1,bool:false},{id:2,bool:true}]
}
// _.assign,它会递归合并
let obj = _.merge(data2,data1)
console.log(obj);
8. 使用echarts
表格
1. 下载插件
cnpm i echarts@4.6.0 -S
最新版本可能会有点问题
2. 引入
import echarts from "echarts";
3. 准备好dom,初始化echarts实例
<div id="table"></div>
<script>
import _ from 'lodash'
import echarts from "echarts";
import { getData } from "@/api/reports.js";
export default {
data() {
return {
options: {
title: {
text: "用户来源",
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
label: {
backgroundColor: "#E9EEF3",
},
},
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: [
{
boundaryGap: false,
},
],
yAxis: [
{
type: "value",
},
],
},
};
},
async mounted() {
// 初始化一个echarts实例
var myChart = echarts.init(document.getElementById("table"));
let { data: res } = await getData();
if (res.meta.status != 200) return this.$message.error(res.meta.msg);
const result = _.merge(res.data, this.options)
myChart.setOption(result)
},
};
</script>
<style lang='scss' scoped>
#table {
width: 750px;
height: 400px;
}
</style>
简单说几个配置项,了解更多可以去echarts官网
title
标题组件
title.show = true 是否显示标题组件
title.text = ‘’ 主标题文本,支持使用\n换行
title.link = ‘’ 主标题文本超链接
title: {
text:'标题',
link: 'https://www.baidu.com',
}
点击标题可以跳转到百度
grid
直角坐标系网格
grid.left/right/top/bottom grid 组件离容器左/右/上/下的距离。
grid.containLabel 它的值为true时为了防止标签溢出
xAxis
X轴
xAxis.type 坐标轴的类型 值为‘value’数值轴,适用于连续数据
xAxis. boundaryGap 坐标轴两边留白
xAxis. boundaryGap =true
xAxis. boundaryGap =false
yAxis
Y轴(与X轴差不多)
tooltip
提示框组件
tooltip. trigger = ‘’ 触发类型 item(数据项图形触发) axis(坐标轴触发) none(什么都不触发)
tooltip. axisPointer 是一个对象
tooltip. axisPointer.type = “cross” 会自动显示axisPointer的label,label默认不显示(也就是默认只显示指示线)
legend
图例组件
legend.data 图例的数据数组
series
series.type 类型
series.name 系列名称,用于tooltip的显示
series.data 系列中的数据内容数组
series.stack 数据堆叠,同个类目轴上系列配置相同的stack值后,后一个系列的值会在前一个系列的值上相加。