后台管理系统 -- 点击导航栏菜单对应的面包屑和标签(Tag)的动态编辑功能

本文详细描述了如何在Vue.js应用中使用Vuex进行面包屑和标签的动态管理,包括存储路由对象、处理路由跳转、更新状态列表以及响应用户交互,确保导航菜单和面包屑/标签组件实时同步。
摘要由CSDN通过智能技术生成

相信很多时候,面包屑和标签(Tag)的功能几乎是后台管理系统标配。

就是会随着路由的跳转来进行相应的动态更新。

我先展示一下效果:

1.面包屑

先说一下思路:

我们导航菜单点击之后,将当前显示路由对象存储到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
            })
        }
    },
})

最后,通过拿到这个列表对象,并进行渲染就达到如上面所示的效果了。

 

2.标签(Tag)

这是大体思路:

1.我们点击导航菜单,将这个路由对象添加到,Tag组件要渲染的标签列表里面(最终这个列表存储到Vux里面,方便被组件拿到)。

2. 我们点击Tag关闭操作时,会在Vuex里面找到对应的路由对象数据,并将他删去。

3.当我们点击Tag标签本体时,跳转到对应的路由页面。

2.1 点击导航菜单,对应tag动态变化

 当我们点击导航菜单的时候,先将对应的路由对象存储到经过updateTagList存储到对应的state里面。

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
		},
	},

2.2 点击关闭按钮,对应的tag动态变化。

我们将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
	
            // 向后跳转
			this.$router.push({ path: nTagList[activeIndex - 1].path })
			// 更新面包屑
			let curMenuList = this.handlerObjConvertAry(nTagList[activeIndex - 1])
			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)
			// 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
		},

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

本郡主是喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值