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

news2024/11/19 10:33:49

相信很多时候,面包屑和标签(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
			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
            })
        }
    },
})

 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1351743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电子负载是如何实现这些功能的

电子负载模拟真实负载的电子设备&#xff0c;它可以吸收或释放电能&#xff0c;以实现对电源、电池、发电机等电源设备的测试和保护。电子负载的主要功能包括恒流、恒压、恒功率、恒电阻等模式&#xff0c;以及过压、过流、短路、过热等保护功能。那么&#xff0c;电子负载是如…

RAL论文:一种自感知扭转塔折纸软体机器人

折纸是一种以纸张折成各种不同形状的艺术活动。折纸与自然科学结合在一起&#xff0c;不仅成为建筑学院的教具&#xff0c;还发展出了折纸几何学成为现代几何学的一个分支。根据折痕的不同分布&#xff0c;可以将纸张折叠成不同的形状&#xff0c;例如有许多经典的折纸结构&…

东信免驱系列身份证阅读器串口通讯协议解析示例,适用于单片机、ARM等系统开发集成使用

完整的一次读卡流程包括&#xff1a; 身份证寻卡 > 身份证选卡 > 身份证读卡&#xff0c;三个步骤 缺一不可&#xff08;见通讯协议&#xff09;。 寻卡&#xff1a;EA EB EC ED 04 00 B0 B4 BB 返回&#xff1a;EA EB EC ED 05 00 00 B0 B5 BB 选卡&#xff1a;EA …

【EI会议征稿通知】2024年第四届数字信号与计算机通信国际学术会议(DSCC 2024)

2024年第四届数字信号与计算机通信国际学术会议&#xff08;DSCC 2024&#xff09; 2024 4th International Conference on Digital Signal and Computer Communications 第四届数字信号与计算机通信国际会议(DSCC 2024)将于2024年4月12日至14日在中国-香港举行。DSCC 2024旨…

Java8新特性 Stream流详解

目录 1、介绍 2、获取Stream流的两种方式 方式一&#xff1a;根据Collection获取流 方式二&#xff1a;Stream中的静态方法of获取流 区别 3、Stream流注意事项 4、Stream流的常用方法 forEach count filter limit skip map sorted distinct match find max和…

【JAVA核心知识】分布式事务框架Seata

Seata 基本信息 GitHub&#xff1a;https://github.com/seata/seatastars: 20.6k 最新版本&#xff1a; v1.6.1 Dec 22, 2022 官方文档&#xff1a;http://seata.io/zh-cn/index.html 注意 官方仅仅支持同步调用。 官方在FAQ中表示对于异步框架需要自行支持。 具体的扩展思…

学习Go语言Web框架Gee总结--上下文Context(二)

学习Go语言Web框架Gee总结--上下文Context context/go.modcontext/main.gocontext/gee/context.gocontext/gee/router.gocontext/gee/gee.go 学习网站来源&#xff1a;Gee 项目目录结构&#xff1a; context/go.mod module examplego 1.21.5require gee v0.0.0 replace gee…

python设计模式:模板方法模式

更多Python学习内容&#xff1a;ipengtao.com 软件设计和编程中&#xff0c;设计模式是一种有助于解决常见问题的强大工具。其中之一是"模板方法模式"&#xff0c;它是一种行为型设计模式&#xff0c;允许你定义一个算法的骨架&#xff0c;但将一些步骤的具体实现延迟…

【elfboard linux开发板】7.i2C工具应用与aht20温湿度寄存器读取

1. I2C工具查看aht20的温湿度寄存器值 1.1 原理图 传感器通过IIC方式进行通信&#xff0c;连接的为IIC1总线&#xff0c;且设备地址为0x38&#xff0c;实际上通过后续iic工具查询&#xff0c;这个设备是挂载在iic-0上 1.2 I2C工具 通过i2c工具可以实现查询i2c总线、以及上面…

第7章 参数估计(重点)

注意&#xff1a;区分正态总体还是非正态总体、总体方差已知还是未知、样本是大样本还是小样本&#xff0c;从而使用对应的Z或者t分布。

面试题理解深层次的数组名

目录 引言 一&#xff1a;一维数组 举例如下 1.铺垫知识 数组名是数组首元素的地址&#xff0c;但是有两个特殊情况 &#xff08;1&#xff09;sizeof(数组名) &#xff08;2&#xff09;&数组名 2.分析讲解上述代码结果 2.字符数组 举例一如下 1.知识铺垫 …

CMake入门教程【基础篇】CMake+Visual Studio2022构建C++项目

文章目录 1.概述2.Visual Studio 2022简介3.安装Visual Studio 20224.安装CMake5.创建CMake项目6. 构建项目 1.概述 CMake和Visual Studio 2022结合 在现代软件开发中&#xff0c;CMake和Visual Studio 2022的结合提供了一个强大的环境&#xff0c;用于构建和管理各种规模的C项…

STM32 学习(二)GPIO

目录 一、GPIO 简介 1.1 GPIO 基本结构 1.2 GPIO 位结构 1.3 GPIO 工作模式 二、GPIO 输出 三、GPIO 输入 1.1 传感器模块 1.2 开关 一、GPIO 简介 GPIO&#xff08;General Purpose Input Output&#xff09;即通用输入输出口。 1.1 GPIO 基本结构 如下图&#xff0…

C++基础:静态变量(保姆级讲解)

1.静态变量定义 在C的&#xff0c;静态变量是一个非常有用的特性&#xff0c;它在程序执行期间只初始化一次&#xff0c;并在程序的整个执行期间都保持其值。 可能这样子说大家无法特别理解&#xff1a;静态变量该怎么定义呢&#xff1f;静态变量的作用是什么&#xff1f;该如…

算法29:不同路径问题(力扣62和63题)--针对算法28进行扩展

题目&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff0…

网络端口(包括TCP端口和UDP端口)的作用、定义、分类,以及在视频监控和流媒体通信中的定义

目 录 一、什么地方会用到网络端口&#xff1f; 二、端口的定义和作用 &#xff08;一&#xff09;TCP协议和UDP协议 &#xff08;二&#xff09;端口的定义 &#xff08;三&#xff09;在TCP/IP体系中&#xff0c;端口(TCP和UDP)的作用 &#xff08;…

Visual Studio 2017 + opencv4.6 + contribute + Cmake(Aruco配置版本)指南

之前配置过一次这个&#xff0c;想起这玩意就难受&#xff0c;贼难配置。由于要用到里面的一个库&#xff0c;不得已再进行配置。看网上的博客是真的难受&#xff0c;这写一块&#xff0c;那里写一块&#xff0c;乱七八糟&#xff0c;配置一顿发现写的都是错的&#xff0c;还得…

leetcode刷题日记:222. Count Complete Tree Nodes(完全二叉树的节点个数)

这一道题&#xff0c;我们可以选择直接进行二叉树的遍历&#xff0c;将所有结点遍历一遍就能得到完全二叉树的结点个数&#xff0c;时间复杂度为O(n)。 代码如下&#xff1a; int countNodes(struct TreeNode* root) {if(rootNULL){return 0;}return countNodes(root->left…

【Linux】socket基础API

目录 1. 创建socket&#xff08;TCP/UDP&#xff0c;客户端服务器&#xff09; 1.1 第一个参数——domain 1.2 第二个参数——type 1.3 第三个参数——protocol 2. 绑定socket地址&#xff08;TCP/UDP&#xff0c;服务器&#xff09; 2.1 字节序及转换函数 2.2 IP地址及…