Vue element-ui el-cascader 只能末级多选问题
作者:囍一
这篇文章主要介绍了Vue element-ui el-cascader 只能末级多选问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
element-ui el-cascader只能末级多选
像这样的需求我们直接可以用css完成
/deep/.el-cascader-panel:first-child .el-checkbox{ display:none; }
扩展实现element-ui中el-cascader全选功能
重所周知,element-ui中的cascader中,没有对所有子节点的全选功能。
近期,公司项目有一个功能是,如果点击了全选,则选中所有子节点的功能;如果在全选状态下,取消了任意一个节点,则移除该节点和全部节点;如果在全选状态下,又点击了全选,则完成全不选的操作,即实现效果如下
图1.1: 从【选中部分节点】(或【所有节点都没有选择】) 到【全选】的实现效果
图1.2 从【已选中全部节点】状态到【取消任意一个节点】效果图
图1.3 全不选效果图(在【全选】状态下再次点击【全选】按钮,或挨个取消已选中节点)
实现思路如下
【Ⅰ】返回数据格式
1. 如果是只有一层字节点,他的数据返回格式应是[节点1, 节点2, .....]
2. 如果含有多层节点,他的数据返回格式应该是[ [父节点,子节点,孙子节点...], [父节点,子节点,孙子节点...] ],这种数据返回格式,可以很清晰的看到各个节点所处的层次结构
【2】全选实现方式
1. 全选状态:包含了所有节点,因为数据结构层次的不确定,可以大致分为两种:
第一种,单层结构,对于全选实现方式很简单,通过更改绑定的数据源,加入所有节点即可;
第二种,多层结构,对于这种数据结构,我们采用递归的方式(不确定是2层,3层.还是更多),首先我们创建一个临时数据,用于保存根节点到各个子节点中所有节点的value值,对于如图所示的11号节点和8号节点,那我们应该保存的值为[ [1, 3, 7, 11], [1, 3, 8] ]
2. 全不选状态:
- 对于这个状态比较简单,将数组清空即可
3. 从全选状态到取消任意一个节点状态:
- 对于这个状态,删除【全选】所对应的节点和删除本次要移除的节点即可
组件源码奉上
<template> <div> <el-cascader v-model="select_options" ref="cascader" :options="options_cascader" :props="getProps" :filterable="filterable" @change="optionsChange" collapse-tags clearable></el-cascader> </div> </template> <script> import cloneDeep from "lodash/cloneDeep"; export default { name: "myCascader", props: { options: { // 级联选择器选项 type: Array, default: [] }, is_deep: { // 是否有children,即数据深度是否为多层 type: Boolean, required: true }, has_all_select: { // 是否为带有全部的选项 type: Boolean, required: true }, all_select_flag: { // '全部'选项的标识 type: String | Number, default: '' }, value: { // 绑定的value值 type: String, default: 'value' }, label: { // 绑定了label值 type: String, default: 'label' }, filterable: { // 是否可以模糊搜索(只能选中最后一层子节点) type: Boolean, default: false } }, mounted() { this.options_cascader = cloneDeep(this.options) // 深拷贝传过来的数据源,引用了lodash包 if (!this.is_deep && this.has_all_select && !this.all_select_flag) { console.warn("当前为单层数据且含有全部选项,请输入全部选项标识,默认为'',如果全部类型的标识为''请忽略") } }, data() { return { options_cascader: [], // 所有选项 select_options: [], // 以选择的节点 is_select_all: false, // 是否为全选 deep_option_data: [] // 缓存各个深度的value } }, computed: { // 获取配置选项 getProps() { return { multiple: true, expandTrigger: 'hover', emitPath: this.is_deep, value: this.value, label: this.label } }, }, methods: { optionsChange() { // 判断已选中的节点中是否包含全部 let has_all_option = false if (!this.is_deep) { has_all_option = this.select_options.includes(this.all_select_flag) } else { has_all_option = this.select_options.some(res => res.length === 1) } /** * 如果已选择节点中包含全部,且is_select_all为true时,代表移除了选项中除全部外的某个节点 * 如果已选择节点中包含全部,且is_select_all为false时,代表选择了全部节点 * 如果已选择节点中不包含全部,且is_select_all为true时,代表取消选择全部节点 * */ if (has_all_option && this.is_select_all) { this.$refs.cascader.$refs.panel.clearCheckedNodes() this.select_options.splice(this.searchSelectAllNodeIndex(), 1) this.is_select_all = false } else if (has_all_option && !this.is_select_all) { this.is_select_all = true this.selectAll() } else if (!has_all_option && this.is_select_all) { this.is_select_all = false this.$refs.cascader.$refs.panel.clearCheckedNodes() this.select_options = [] } this.$emit('getOptions', this.select_options) }, // 查找全部节点所在的索引 searchSelectAllNodeIndex() { if (!this.is_deep) { return this.select_options.indexOf(this.all_select_flag) } else { let selectAllOptionIndex = -1 this.select_options.forEach((res, index) => { if (res.length === 1) { selectAllOptionIndex = index } }) return selectAllOptionIndex } }, // 选择全部 selectAll() { this.select_options = [] if (!this.is_deep) { // 为单层数据,即没有children this.options_cascader.forEach(res => { this.select_options.push(res[this.value]) }) } else { // 多层数据, 递归 this.getDeepOptions(this.options_cascader) } }, // 递归获取深层数据 getDeepOptions(value) { let arr value.forEach(res => { if (res.children) { // 如果不是最后一层,则缓存当前层次的value this.deep_option_data.push(res[this.value]) this.getDeepOptions(res.children) } else { // 如果是最后一层,把最后一层的value放入级联选择器绑定的数组 arr = cloneDeep(this.deep_option_data) arr.push(res[this.value]) this.select_options.push(arr) } }) // 每一层循环结束后,清空本层的父节点 this.deep_option_data.pop() } } } </script> <style scoped> </style>
使用方法
// 多层结构,带全部 <my-cascader :options="options" :is_deep="true" :has_all_select="true" @getOptions="getOptions"> </my-cascader> // 单层结构,带全部 <my-cascader :options="options" :is_deep="false" :has_all_select="true" @getOptions="getOptions"> </my-cascader> // 注:如果不需要配置全部节点则直接使用element提供的cascader即可 // 本组件只考虑第一层带有全部的情况,且全部节点不带有children属性,即只有一层,若除第一层节点外其他层次节点带有全部选项,则勾选本层次的上一层节点即可
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。