相信很多时候,面包屑和标签(Tag)的功能几乎是后台管理系统标配。
就是会随着路由的跳转来进行相应的动态更新。
我先展示一下效果:
先说一下思路:
我们导航菜单点击之后,将当前显示路由对象存储到Vuex的storge里面,然后在面包屑组件里面,读取这个状态即可。
?我的导航菜单使用的路由对象数据格式,主要起作用的是?path,label字段。
?
下面我们实际,就是点击导航菜单跳转的时候,有些是有父路由的,比如用户管理,但是我要和比如首页(根路由),做相同的逻辑处理,因此下面我们传参的时候,将用户管理的父路由封装成parent属性。
当我们去处理这个路由对象的时候,由于最后要被面包屑渲染的组件的数据是一个列表的形式,因此对传入路由对象,通过handlerObjConvertAry方法处理,将路由对象转换为对应的列表(curMenuList)
?面包屑组件
clickMenu(item) {
this.$router.push({ path: item.path })
// 卧槽,一个是item.path;怎么哦安短他是子路由,并且拿到其中的值
let curMenuList = this.handlerObjConvertAry(item)
// debugger
this.$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
})
}
},
})
最后,通过拿到这个列表对象,并进行渲染就达到如上面所示的效果了。
?
这是大体思路:
1.我们点击导航菜单,将这个路由对象添加到,Tag组件要渲染的标签列表里面(最终这个列表存储到Vux里面,方便被组件拿到)。
2. 我们点击Tag关闭操作时,会在Vuex里面找到对应的路由对象数据,并将他删去。
3.当我们点击Tag标签本体时,跳转到对应的路由页面。
?当我们点击导航菜单的时候,先将对应的路由对象存储到Vuex中的updateTagList里面。
clickMenu(item) {
this.$router.push({ path: item.path })
// 卧槽,一个是item.path;怎么哦安短他是子路由,并且拿到其中的值
let curMenuList = this.handlerObjConvertAry(item)
// debugger
this.$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
},
},
我们将tag对应的路由对象,先获取一次数据,先遍历找到在vuex列表里面对应的索引值。找到了,并且删除这个路由对象。然后,再次获取vuex中的tageList数据。如果tagLsit的长度为1了,说明只剩下首页路由对象一个了,我们跳转到首页。如果不为1,跳转我们删除索引的那个位置。
handlerTagClose(tag) {
let oTagList = this.$store.state.tagList
let activeIndex = null
oTagList.forEach((item, index) => {
// 找出删除元素的索引
if (item.path == tag.path) {
activeIndex = index
}
})
this.$store.commit('removeTag', tag.path) // 删除元素
let nTagList = this.$store.state.tagList
if (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
})
}
},
})
就是绑定一个点击事件,将tag对应路由对象,点击实现跳转。
handlerTagClick(tag) {
this.$router.push({ path: tag.path })
let curMenuList = this.handlerObjConvertAry(tag)
// debugger
this.$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
},
<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>