相信很多时候,面包屑和标签(Tag)的功能几乎是后台管理系统标配。
就是会随着路由的跳转来进行相应的动态更新。
我先展示一下效果:
1.面包屑
先说一下思路:
我们导航菜单点击之后,将当前显示路由对象存储到Vuex的storge里面,然后在面包屑组件里面,读取这个状态即可。
我的导航菜单使用的路由对象数据格式,主要起作用的是 path,label字段。
下面我们实际,就是点击导航菜单跳转的时候,有些是有父路由的,比如用户管理,但是我要和比如首页(根路由),做相同的逻辑处理,因此下面我们传参的时候,将用户管理的父路由封装成parent属性。
当我们去处理这个路由对象的时候,由于最后要被面包屑渲染的组件的数据是一个列表的形式,因此对传入路由对象,通过handlerObjConvertAry方法处理,将路由对象转换为对应的列表(curMenuList)
面包屑组件
clickMenu(item) {this.$router.push({ path: item.path })// 卧槽,一个是item.path;怎么哦安短他是子路由,并且拿到其中的值let curMenuList = this.handlerObjConvertAry(item)// debuggerthis.$store.commit('updateCurMenuList', curMenuList)// 将路由对象存储到Vuex的store里面this.$store.commit('updateTagList', item)console.log(this.$route)},
/** 将tag格式转换为 [{path:'',name:'',..}, {path:'',..}]** @param item {path:'',name',parent:{path:'',name:''}}* @return*/handlerObjConvertAry(item) {let ary = []item.parent ? ary.push({ ...item.parent }) : {}ary.push({ ...item })return ary},
然后,将这个curMenuList,替换到Vuex中的curMenuList。
const store = new Vuex.Store({state: {curMenuList: [],tagList: [{path: '/index',name: 'index',label: '首页'}]},mutations: {updateCurMenuList(state, curMenuList) {state.curMenuList = curMenuList.filter((item) => {return item.path != '/index' //由于首页不是列表数据,而是固定写死数据,因此过滤/index,防止我们重复添加})},updateTagList(state, tag) {for (let i = 0; i < state.tagList.length; i++) {const oTag = state.tagList[i];if (oTag.path == tag.path) {return}}state.tagList.push(tag)},removeTag(state, path) {state.tagList = state.tagList.filter((item, index) => {return item.path != path})}},
})
最后,通过拿到这个列表对象,并进行渲染就达到如上面所示的效果了。
2.标签(Tag)
这是大体思路:
1.我们点击导航菜单,将这个路由对象添加到,Tag组件要渲染的标签列表里面(最终这个列表存储到Vux里面,方便被组件拿到)。
2. 我们点击Tag关闭操作时,会在Vuex里面找到对应的路由对象数据,并将他删去。
3.当我们点击Tag标签本体时,跳转到对应的路由页面。
2.1 点击导航菜单,对应tag动态变化
当我们点击导航菜单的时候,先将对应的路由对象存储到Vuex中的updateTagList里面。
clickMenu(item) {this.$router.push({ path: item.path })// 卧槽,一个是item.path;怎么哦安短他是子路由,并且拿到其中的值let curMenuList = this.handlerObjConvertAry(item)// debuggerthis.$store.commit('updateCurMenuList', curMenuList)// 将路由对象存储到Vuex的store里面this.$store.commit('updateTagList', item)console.log(this.$route)},
在Vuex的updateTagList方法里面,如果数据已经存在了,我们遍历找到并终止函数调用,然后防止将路由对象存储到对应的 tagList里面。如果数据没存在,我们将数据成功添加。
const store = new Vuex.Store({state: {curMenuList: [],
// ps-------------tagList: [{path: '/index',name: 'index',label: '首页'// ...}]},mutations: {updateCurMenuList(state, curMenuList) {state.curMenuList = curMenuList.filter((item) => {return item.path != '/index'})},
// ps----------------updateTagList(state, tag) { // 如果该路由对象已经在Vuex里面存在,我们就终止函数调用for (let i = 0; i < state.tagList.length; i++) {const oTag = state.tagList[i];if (oTag.path == tag.path) {return}}state.tagList.push(tag)},removeTag(state, path) {state.tagList = state.tagList.filter((item, index) => {return item.path != path})}},
})
由于我们Vuex中的数据更新,因此这个组件会被重新渲染。
<template><div class="tag"><el-tag:key="tag.path"v-for="(tag, index) in tagList":closable="index != 0"@close="handleClose(tag)"@click="handleClick(tag)"style="float: left; margin: 0 0 0 5px":effect="tag.path === $route.path ? 'dark' : 'light'">{{ tag.label }}</el-tag></div>
</template>
computed: {getTagList() {return this.$store.state.tagList},},
2.2 点击关闭按钮,对应的tag动态变化。
我们将tag对应的路由对象,先获取一次数据,先遍历找到在vuex列表里面对应的索引值。找到了,并且删除这个路由对象。然后,再次获取vuex中的tageList数据。如果tagLsit的长度为1了,说明只剩下首页路由对象一个了,我们跳转到首页。如果不为1,跳转我们删除索引的那个位置。
handlerTagClose(tag) {let oTagList = this.$store.state.tagListlet activeIndex = nulloTagList.forEach((item, index) => {// 找出删除元素的索引if (item.path == tag.path) {activeIndex = index}})this.$store.commit('removeTag', tag.path) // 删除元素let nTagList = this.$store.state.tagListif (nTagList.length == 1) {// 如果剩余1(只剩首页,跳转首页)activeIndex = 0}this.$router.push({ path: nTagList[activeIndex].path })// 更新面包屑let curMenuList = this.handlerObjConvertAry(nTagList[activeIndex])this.$store.commit('updateCurMenuList', curMenuList)},
//...........handlerObjConvertAry(item) {let ary = []item.parent ? ary.push({ ...item.parent }) : {}ary.push({ ...item })return ary},
const store = new Vuex.Store({state: {curMenuList: [],tagList: [{path: '/index',name: 'index',label: '首页'}]},mutations: {updateCurMenuList(state, curMenuList) {state.curMenuList = curMenuList.filter((item) => {return item.path != '/index'})},updateTagList(state, tag) {for (let i = 0; i < state.tagList.length; i++) {const oTag = state.tagList[i];if (oTag.path == tag.path) {return}}state.tagList.push(tag)},// PS ------------removeTag(state, path) {state.tagList = state.tagList.filter((item, index) => {return item.path != path})}},
})
2.3 点击tag标签,实现路由跳转。
就是绑定一个点击事件,将tag对应路由对象,点击实现跳转。
handlerTagClick(tag) {this.$router.push({ path: tag.path })let curMenuList = this.handlerObjConvertAry(tag)// debuggerthis.$store.commit('updateCurMenuList', curMenuList)},/** 将tag格式转换为 [{path:'',name:'',..}, {path:'',..}]** @param item {path:'',name',parent:{path:'',name:''}}* @return*/handlerObjConvertAry(item) {let ary = []item.parent ? ary.push({ ...item.parent }) : {}ary.push({ ...item })return ary},
2.4 点击tag高亮显示
<el-tag:key="tag.path"v-for="(tag, index) in tagList":closable="index != 0"@close="handleClose(tag)"@click="handleClick(tag)"style="float: left; margin: 0 0 0 5px"// 当前路由路径 == tag标签所映射的路由对象路径,既可以:effect="tag.path === $route.path ? 'dark' : 'light'">{{ tag.label }}</el-tag>