对el-cascader二次封装实现双击父节点,全选该父节点下的子节点,并且父子节点互不影响,如下图
思路:既然能够取消子节点不影响父节点,就需要将checkStrictly属性置为true,通过方法实现双击父节点选中所有子节点,此外不点击多选框实现选中效果,需要用到cascader中node对象原型上的doCheck方法(element官网文档并没有直接给到如何修改状态的方法,通过查看cascader-panel.js源码发现)
一、使用插槽自定义结构
第一步是使用插槽自定义结构,及data中定义的变量
<el-cascader v-model="value" :props="props" :options="options" ref="cascader" clearable>
<template slot-scope="{ node,data }">
<div @dblclick="handleMoreChoice(node)">{{ data.label }}</div>
</template>
</el-cascader>
二、能够多选并且父子之间不互相关联
根据element官网文档需要将这两个属性添加上
props: { multiple: true, checkStrictly: true },
三、实现双击父节点子节点全选
handleMoreChoice(node) {
this.value = this.value.slice(0) //slice方法是为了触发value反显到input框中,并且不改变原数组
const nodeList = this.getNodeChildren(node);
// 取消选中
if (node.checked) {
nodeList.forEach(item => {
item.doCheck(false)
if (this.value.includes(item.path)) {
this.value.splice(this.value.indexOf(item.path), 1)
}
})
} else { // 确认选中
nodeList.forEach(item => {
item.doCheck(true)
if (!this.value.includes(item.path)) {
this.value.push(item.path)
}
})
}
},
//获取所有子级
getNodeChildren(node) {
let childrenNode = []
function getChildren(data) {
childrenNode.push(data)
if (data.children.length) {
for (let index = 0; index < data.children.length; index++) {
getChildren(data.children[index])
}
}
}
getChildren(node)
return childrenNode
},
上述代码在没有使用slice方法之前,只是实现了双击父节点选中子节点,但是input框中并没有反显相应数据,推测可能是value新添加的数据不是响应式的,但是使用this.$forceUpdate()或者this.$set()都不能达到效果,此时想到vue2官网文档中
所以使用slice方法,亲测concat方法同样生效,但与此同时,就会导致父节点双击选中,页面中子节点对应的dom结构会隐藏,但效果实现了,如上边GIF所示,这个问题暂时没有想到解决方法
四、下面为完整代码
<template>
<div>
<el-cascader v-model="value" :props="props" :options="options" ref="cascader" clearable>
<template slot-scope="{ node,data }">
<div @dblclick="handleMoreChoice(node)">{{ data.label }}</div>
</template>
</el-cascader>
</div>
</template>
<script>
export default {
data() {
return {
props: { multiple: true, checkStrictly: true },
value: [],
options: [
{
value: 'zhinan',
label: '指南',
children: [
{
value: 'shejiyuanze',
label: '设计原则',
children: [{
value: 'yizhi',
label: '一致',
children: [
{
value: "test1",
label: "测试1"
},
{
value: "test2",
label: "测试2"
},
]
}, {
value: 'fankui',
label: '反馈',
children: [
{
value: "test3",
label: "测试3"
},
{
value: "test4",
label: "测试4"
},
]
}]
},
{
value: 'daohang',
label: '导航',
children: [{
value: 'cexiangdaohang',
label: '侧向导航'
}, {
value: 'dingbudaohang',
label: '顶部导航'
}]
},
]
},
{
value: 'zhinan0',
label: '指南0',
children: [
{
value: 'shejiyuanze0',
label: '设计原则0',
children: [{
value: 'yizhi0',
label: '一致0'
}, {
value: 'fankui0',
label: '反馈0'
}, {
value: 'xiaolv0',
label: '效率0'
}, {
value: 'kekong0',
label: '可控0'
}]
},
{
value: 'daohang0',
label: '导航0',
children: [{
value: 'cexiangdaohang0',
label: '侧向导航0'
}, {
value: 'dingbudaohang0',
label: '顶部导航0'
}]
},
]
},
]
}
},
methods: {
handleMoreChoice(node) {
this.value = this.value.slice(0) //slice方法是为了触发value反显到input框中,并且不改变原数组
const nodeList = this.getNodeChildren(node);
// 取消选中
if (node.checked) {
nodeList.forEach(item => {
item.doCheck(false)
if (this.value.includes(item.path)) {
this.value.splice(this.value.indexOf(item.path), 1)
}
})
} else { // 确认选中
nodeList.forEach(item => {
item.doCheck(true)
if (!this.value.includes(item.path)) {
this.value.push(item.path)
}
})
}
},
//获取所有子级
getNodeChildren(node) {
let childrenNode = []
function getChildren(data) {
childrenNode.push(data)
if (data.children.length) {
for (let index = 0; index < data.children.length; index++) {
getChildren(data.children[index])
}
}
}
getChildren(node)
return childrenNode
},
},
}
</script>
<style lang="less" scoped>
// /deep/ input {
// width: 100vw !important;
// }
</style>
还有点优化空间,有时间再继续更新。。。。。