element-ui的el-cascader增加全选按钮实现(附源码)
最近遇到了在级联选择器上添加全选框的需求 ,但是项目使用的是Vue2 + Element UI的架构,而我们都知道Element UI提供的级联选择器el-cascader是不支持全选框的,而我又没有在网上找到适合我项目的实现,索性自己实现一个组件(源码附在文末,需要自取)
实现效果:
主要功能实现:
1. 全选按钮可选
通过属性 showAllNode 控制在多选模式下全选按钮的添加与否(注意,单选模式下没有全选按钮):
props: {showAllNode: {type: Boolean,default: false}
},
methods: {
async fetchDictTree() {let children = this.data.data[0].children || []// 添加全选节点this.treeData = this.showAllNode ? [this.allNode, ...children] : children// 获取所有节点值(一维数组)this.allNodeValues = this.getAllNodeValues()// 修改初始化逻辑if (this.showAllNode) {// 选中所有节点(包括全选节点)this.selectedValue = ['0', ...this.allNodeValues]this.lastSelectedValue = [...this.selectedValue]} else {this.selectedValue = []this.lastSelectedValue = []}this.$emit('input', this.selectedValue)this.$emit('ready', true)},
}
2. 全选按钮与其他节点的联动效果:
- 点击全选按钮所有节点都被选中,非全选状态下全选按钮不被选中
if (this.showAllNode) {// 检查是否包含全选节点const hasAll = value.includes('0')const prevHasAll = this.lastSelectedValue.includes('0')if (hasAll && !prevHasAll) {// 选中全选,同时选中所有节点const allValues = ['0', ...this.allNodeValues]this.selectedValue = allValuesthis.lastSelectedValue = [...allValues]// 只返回 ['0'] 表示全选this.$emit('input', ['0'])this.$emit('change', ['0'])return} else if (!hasAll && prevHasAll) {// 取消全选,清空所有选中setTimeout(() => {this.selectedValue = []this.lastSelectedValue = []this.$emit('input', [])this.$emit('change', [])}, 0)return}// 检查是否所有节点都被选中const allSelected = this.allNodeValues.every(nodeValue =>value.includes(nodeValue))// 如果所有节点都被选中,但全选节点没有被选中,则添加全选节点if (allSelected && !hasAll) {const newValue = ['0', ...value]this.selectedValue = newValuethis.lastSelectedValue = [...newValue]// 只返回 ['0'] 表示全选this.$emit('input', ['0'])this.$emit('change', ['0'])return}// 如果不是所有节点都被选中,但全选节点被选中了,则移除全选节点if (!allSelected && hasAll) {const newValue = value.filter(v => v !== '0')this.selectedValue = newValuethis.lastSelectedValue = [...newValue]this.$emit('input', newValue)this.$emit('change', newValue)return}}
3. 全选按钮选中时传回的节点数据(dictKey)的值为0而非所有节点key值
watch: {value: {handler(val) {// 如果传入的值是 ['0'],表示选中全选节点if (Array.isArray(val) && val.length === 1 && val[0] === '0' && this.showAllNode) {// 内部选中所有节点this.selectedValue = ['0', ...this.allNodeValues]} else if (!this.multiple && Array.isArray(val) && val.length === 1) {// 单选模式下,如果传入的是数组,取第一个元素this.selectedValue = val[0]} else {this.selectedValue = val}},immediate: true},},
组件使用:
<template><div><classify-cascader v-model="classify" placeholder="请选择试卷分类" multiplecheckStrictly show-all-node width="200px" /></div>
</template><script>
import classifyCascader from '@/components/classify-cascader/index.vue'export default {name: 'indexVue',components: {classifyCascader},data() {return {classify: []}}
}
</script>
- 笔者已经分装好了一个组件,可以直接使用,如果下拉框的数据是从后端获取的话,改一下fetchDictTree() 方法中 children 的数据赋值代码就可以,类似于:
const { data } = await APIgetDictTree(params)
let children = data.data[0].children || []
组件实现:
<template><el-cascader v-model="selectedValue" :options="treeData" :props="cascaderProps" :placeholder="placeholder":disabled="disabled" :clearable="clearable" :style="{ width: width }" collapse-tags @change="handleChange" />
</template><script>export default {name: 'ClassifyCascader',props: {value: {type: [String, Array],default: () => []},checkStrictly: {type: Boolean,default: false},multiple: {type: Boolean,default: false},showAllNode: {type: Boolean,default: false},disabled: {type: Boolean,default: false},placeholder: {type: String,default: '请选择'},clearable: {type: Boolean,default: true},width: {type: String,default: '200px'}},data() {return {treeData: [],selectedValue: this.value,cascaderProps: {value: 'dictKey',label: 'dictValue',children: 'children',checkStrictly: this.checkStrictly,multiple: this.multiple,emitPath: false},allNode: {dictKey: '0',dictValue: '全选'},lastSelectedValue: [],allNodeValues: [], // 存储所有节点的值(一维数组)data: {data: [{children: [{dictKey: '1',dictValue: '分类1'},{dictKey: '2',dictValue: '分类2',children: [{dictKey: '2-1',dictValue: '子分类2-1',children: []},{dictKey: '2-2',dictValue: '子分类2-2',children: []}]}]}]}}},watch: {value: {handler(val) {// 如果传入的值是 ['0'],表示选中全选节点if (Array.isArray(val) && val.length === 1 && val[0] === '0' && this.showAllNode) {// 内部选中所有节点this.selectedValue = ['0', ...this.allNodeValues]} else if (!this.multiple && Array.isArray(val) && val.length === 1) {// 单选模式下,如果传入的是数组,取第一个元素this.selectedValue = val[0]} else {this.selectedValue = val}},immediate: true},},created() {this.fetchDictTree()},methods: {// 刷新数据refreshData() {return this.fetchDictTree()},async fetchDictTree() {let children = this.data.data[0].children || []// 添加全选节点this.treeData = this.showAllNode ? [this.allNode, ...children] : children// 获取所有节点值(一维数组)this.allNodeValues = this.getAllNodeValues()// 修改初始化逻辑if (this.showAllNode) {// 选中所有节点(包括全选节点)this.selectedValue = ['0', ...this.allNodeValues]this.lastSelectedValue = [...this.selectedValue]} else {this.selectedValue = []this.lastSelectedValue = []}this.$emit('input', this.selectedValue)this.$emit('ready', true)},handleChange(value) {if (this.showAllNode) {// 检查是否包含全选节点const hasAll = value.includes('0')const prevHasAll = this.lastSelectedValue.includes('0')if (hasAll && !prevHasAll) {// 选中全选,同时选中所有节点const allValues = ['0', ...this.allNodeValues]this.selectedValue = allValuesthis.lastSelectedValue = [...allValues]// 只返回 ['0'] 表示全选this.$emit('input', ['0'])this.$emit('change', ['0'])return} else if (!hasAll && prevHasAll) {// 取消全选,清空所有选中setTimeout(() => {this.selectedValue = []this.lastSelectedValue = []this.$emit('input', [])this.$emit('change', [])}, 0)return}// 检查是否所有节点都被选中const allSelected = this.allNodeValues.every(nodeValue =>value.includes(nodeValue))// 如果所有节点都被选中,但全选节点没有被选中,则添加全选节点if (allSelected && !hasAll) {const newValue = ['0', ...value]this.selectedValue = newValuethis.lastSelectedValue = [...newValue]// 只返回 ['0'] 表示全选this.$emit('input', ['0'])this.$emit('change', ['0'])return}// 如果不是所有节点都被选中,但全选节点被选中了,则移除全选节点if (!allSelected && hasAll) {const newValue = value.filter(v => v !== '0')this.selectedValue = newValuethis.lastSelectedValue = [...newValue]this.$emit('input', newValue)this.$emit('change', newValue)return}}// 正常情况下的处理this.lastSelectedValue = [...value]const outputValue = Array.isArray(value) ? value : [value]this.$emit('input', outputValue)this.$emit('change', outputValue)},// 获取所有节点的值(一维数组)getAllNodeValues() {const allValues = []const traverse = (nodes) => {nodes.forEach(node => {if (node.dictKey === '0') returnallValues.push(node.dictKey)if (node.children && node.children.length > 0) {traverse(node.children)}})}traverse(this.treeData)return allValues}}
}
</script>
大家有什么问题可以评论区交流一下,我看到了也会回复的。
相关文章:

element-ui的el-cascader增加全选按钮实现(附源码)
最近遇到了在级联选择器上添加全选框的需求 ,但是项目使用的是Vue2 Element UI的架构,而我们都知道Element UI提供的级联选择器el-cascader是不支持全选框的,而我又没有在网上找到适合我项目的实现,索性自己实现一个组件…...

Scratch游戏 | 企鹅大乱斗
有没有过无聊到抓狂的时刻?试试这款 企鹅大乱斗 吧!超简单的玩法,让你瞬间告别无聊! 🎮 玩法超简单 等待屏幕出现 ”Go!” 疯狂点击,疯狂拍打企鹅! 💥 游戏特色 解压神器&#x…...
游戏行业DDoS攻击类型及防御分析
游戏行业作为DDoS攻击的高发领域,攻击类型复杂多样,结合多个来源的信息,以下是其主要攻击类型及特征分析: 1. 传统流量型DDoS攻击 UDP洪水攻击:通过大量UDP报文淹没服务器端口,消耗带宽资源,导…...

Uniapp中小程序调用腾讯地图(获取定位地址)
1、先配置权限: 这是上图的代码: "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } } 第二步:写代码: //下面是uniapp的模版代码 主…...

2025全网首发:ComfyUI整合GPT-Image-1完全指南 - 8步实现AI图像创作革命
ComfyUI整合GPT-Image-1完全指南:8步实现AI图像创作革命【2025最新】 OpenAI最新发布的GPT-Image-1模型(也就是ChatGPT-4o背后的图像生成技术)已经通过API开放使用,而令人惊喜的是,ComfyUI已经第一时间提供了完整支持&…...
利用SAP aATP产品分段策略应对订单关税挑战
本文探讨了如何通过在SAP S/4HANA系统中结合**产品分段(Product Segmentation)与高级可承诺性(aATP)**功能,帮助企业在全球化贸易中更有效地处理关税问题,并提升订单承诺的精准性。 产品分段与原产国&…...

工业4.0神经嫁接术:ethernet ip转profinet协议通信步骤图解
在现代工业自动化领域,不同品牌的设备和协议之间的兼容性问题一直是个挑战。我们的包装线项目就遇到了这样的难题:需要将Rockwell Allen-Bradley的EtherNet/IP伺服系统与西门子PLC的PROFINET主站进行无缝对接。为了解决这一问题,我们采用了et…...
深入理解反序列化攻击:原理、示例与利用工具实战
反序列化漏洞是现代 Web 安全中的一个高危攻击类型,常常导致远程代码执行(RCE)、文件读写、身份伪造等严重后果。本文将从基础原理讲起,结合实际代码和工具(PHPGGC、ysoserial)演示反序列化攻击的完整过程。…...
Qt原型模式实现与应用
在Qt中实现原型模式(Prototype Pattern)可以通过以下步骤完成。该模式的核心是通过克隆现有对象来创建新对象,而非通过传统的构造函数。以下是详细说明和示例: 1. 原型模式的核心概念 目的:避免重复初始化对象的高成本…...
Java详解LeetCode 热题 100(17):LeetCode 41. 缺失的第一个正数(First Missing Positive)详解
文章目录 1. 题目描述2. 理解题目3. 解法一:排序法(不满足题目要求)3.1 思路3.2 Java代码实现3.3 代码详解3.4 复杂度分析3.5 不足之处 4. 解法二:哈希表法4.1 思路4.2 Java代码实现4.3 代码详解4.4 复杂度分析4.5 不足之处 5. 解…...
[Java实战]Spring Boot + Netty 实现 TCP 长连接客户端及 RESTful 请求转发(二十六)
[Java实战]Spring Boot Netty 实现 TCP 长连接客户端及 RESTful 请求转发(二十六) 在现代微服务架构中,经常需要在不同服务之间进行高效、可靠的通信。本文将介绍如何使用 Spring Boot 结合 Netty 实现一个 TCP 长连接客户端,并…...

【Linux】动静态库的使用
📝前言: 这篇文章我们来讲讲Linux——动静态库的使用 🎬个人简介:努力学习ing 📋个人专栏:Linux 🎀CSDN主页 愚润求学 🌄其他专栏:C学习笔记,C语言入门基础&…...

Java基础(网络编程)
一、概述 目的:网络通信: 1、设备和设备 2、进程和进程 1)不同设备之间 2)本地设备之间 需要解决的问题: 如何准确地发送到对方的主机 - IP地址 - 唯一的定位网络中的一台主机 如何准确的发送到对方主机的进程 -…...

计量——异方差的检验及其修正
目录 1.异方差的检验 1 BP检验 2white检验 2.异方差的修正 1.异方差的检验 1 BP检验 选择检验方法:BP BP检验的实际步骤(非机器): 1.y对所有x进行回归,得到残差u。计算残差的平方u^2 2.u^2对所有x进行回归&#…...

学习C++的好书:C++编程之禅
历时四个月,把这本书看了一遍,受益匪浅,推荐给大家,系统的学习一遍C。...

OpenCV进阶操作:人脸检测、微笑检测
文章目录 前言一、OpenCV如何实现人脸检测1、haar特征2、级联分类器3、级联分类器的使用 二、人脸检测、微笑检测 案例实现1、预处理2、加载分类器3、标注人脸4、运行结果:4、微笑检测 总结 前言 要实现人脸识别首先要判断当前图像中是否出现了人脸,这就…...

车载诊断进阶篇 --- 车载诊断概念
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...

制作一款打飞机游戏49:敌人抖动
蛇形敌人 如果你玩过一些射击游戏(shmups),尤其是老式的射击游戏,你可能会遇到一种敌人,它们像蛇一样移动。我想在我们的游戏中实现这种效果。这种动态的感觉非常棒,我们完全有能力通过动画来实现它。 方…...
elementplus el-tree 二次封装支持配置删除后展示展开或折叠编辑复选框懒加载功能
本文介绍了基于 ElementPlus 的 el-tree 组件进行二次封装的 TreeView 组件,使用 Vue3 和 JavaScript 实现。TreeView 组件通过 props 接收树形数据、配置项等,支持懒加载、节点展开/收起、节点点击、删除、编辑等操作。组件内部通过 ref 管理树实例&…...

Pycharm IDEA加载大文件时报错:The file size exceeds configured limit
解决方案:配置一下idea.properties文件 文件里面写入代码: idea.max.intellisense.filesize50000重启IDEA即可;...
free void* 指令
https://stackoverflow.com/questions/2182103/is-it-ok-to-free-void free(ptr) 仅释放指针指向的内存,不会修改指针变量本身的值。调用后,ptr 仍然指向原来的地址(称为 "悬空指针"),但该地址对应的内存已…...

PDA手持终端应用有哪些?
随着技术进步不断拓展,PDA手持终端其便携性与多功能特性使其成为多行业数字化转型的核心工具。主要包括物流与仓储管理、零售行业、医疗行业以及制造业等。 1.物流与仓储管理 在物流与仓储管理中,PDA手持终端主要用于物品的实时跟踪、库存管理和拣货作业…...
Python模块化编程
Python模块化编程 记得我刚学Python那会儿,特别喜欢把所有代码都写在一个文件里。直到有一天,我的项目膨胀到了2000多行代码,每次修改都要翻半天…这才痛定思痛,开始研究模块化编程。今天就跟大家聊聊这个让代码变得优雅的魔法。…...
Linux性能分析工具perf
perf 工具详解 perf(Performance Counters for Linux)是 Linux 系统上的一个强大的性能分析工具,用于监控和分析系统及应用程序的性能。它基于 Linux 内核的 Performance Event Subsystem(perf_events),能…...
Android开发-使用内容组件获取通讯信息
在Android开发中,访问和处理用户的通讯信息(如联系人、通话记录等)是一项常见的需求。通过使用Android的内容提供者(ContentProvider),开发者可以方便地查询这些数据,并将其集成到自己的应用中。…...
文件目录与检索综合练习题
文章目录 前言一、基础部分二、参数应用三、参数进阶四、组合应用五、归档压缩六、统计与分析总结 前言 这部分练习题帮助大家更好的掌握命令 一、基础部分 1.用grep在error.log中查找所有含"Timeout"的行 2.使用find在/var/log下搜索7天内修改过的.log文件 3.对da…...

Python+Selenium爬虫:豆瓣登录反反爬策略解析
1. 引言 在当今互联网时代,数据抓取(爬虫)技术广泛应用于数据分析、市场调研、自动化测试等领域。然而,许多网站采用动态加载技术(如Ajax、React、Vue.js等框架)来渲染页面,传统的**<font s…...
信息系统运行管理员:临阵磨枪版
信息系统运行管理员考试 - 全覆盖详细背诵大纲 (根据考情分析和原始材料,力求完整覆盖考点细节) 第一部分:基础知识与运维概览 Chapter 1: 信息系统运维概述 (上午题 5分) 信息: 含义:香农 - 减少随机不确定性的东西;…...

电总协议调试助手更新-PowerBus-v1.0.5
电总协议调试助手,该工具主要是用于打包电总协议,用于电总协议的设备调试(精密空调、UPS、基站电源等等)。电总协议校验计算、编码转换比较麻烦,手动组包困难,使用该工具可以大大提高调试效率。 Ver1.0.5版…...

技术文档:变频器干扰问题与解决方案
1. 引言 在现代工业自动化系统中,变频器(Variable Frequency Drive, VFD)因其高效节能和精确调速的特点被广泛应用于电机控制。然而,变频器在运行过程中会产生高频电磁干扰(EMI),对周边设备如P…...