问题描述
element2.15.14
el-cascade的默认效果是平级的例如:
但通常级联是由层级的例如:
由于element似乎没有这个选项这里自己实现一下。
解决思路
首先观察dom结构发现每一级都会产生一个el-cascader-menu
的节点,也就是说只要将该节点向下移动即可,这里我使用transform:translateY(...)
来做平移。
那么什么时候移动、移动多少呢?
通过@expand-change
事件我们可以在节点展开的时候获取各父级选项值组成的数组例如:[ 1,2 ]
通过该数组我们可以计算出移动的距离。
这个距离有两个部分 偏移量 = 单个偏移量 + 上一次的偏移量
计算代码如下
deptExpandChange(options, val) {
this.$nextTick(() => {
// 兼容多个部门cascader时
let deptPopperContainers = document.querySelectorAll('body > .deptPopperContainer');
let el = deptPopperContainers[deptPopperContainers.length - 1];
let menuList = el.querySelectorAll('.deptPopperContainer .el-cascader-menu');
let clickIndex = val.length - 1;
let operatorIndex = val.length;
let offsetY = 30;
// 计算单个偏移量
let list = options;
let count = 0;
// 深度
for (let i = 0; i < operatorIndex; i++) {
// 广度
for (let j = 0; j < list.length; j++) {
if (list[j].id == val[i]) {
count = j;
break;
}
}
list = list[count].children;
}
count = count > 5 ? 5 : count;
// 计算上一次偏移量
let lastOffset = 0;
if (menuList[clickIndex].style.transform) {
lastOffset = parseInt(menuList[clickIndex].style.transform.slice(11));
}
if (menuList[operatorIndex]) {
menuList[operatorIndex].style.transform = `translateY(${(count) * offsetY + lastOffset}px)`
}
})
}
这里需要注意的点
- offsetY 控制偏移的程度
- (count) * offsetY + lastOffset 如果改为 (count+1) * offsetY + lastOffset 则第一级别也会产生偏移
- 该方法使用了二重循环,复杂的为n^2,当节点过深过广时
可能出现卡顿 请谨慎选择
完整demo
<template>
<div class="app-container">
<el-cascader
v-model="deptId"
:options="deptOptions"
:show-all-levels="false"
:props="{
value: 'id',
expandTrigger: 'hover',
checkStrictly: true,
emitPath: false,
}"
popper-class="deptPopperContainer"
size="small"
clearable
@expand-change="deptExpandChange(deptOptions, $event)"
>
</el-cascader>
</div>
</template>
<script>
export default {
data() {
return {
deptId: null,
deptOptions: [
{
id: 1,
label: "总部",
children: [
{
id: 2,
label: "技术部",
children: [
{
id: 5,
label: "前端开发组",
},
{
id: 6,
label: "后端开发组",
},
],
},
{
id: 3,
label: "市场部",
children: [
{
id: 7,
label: "销售团队",
},
{
id: 8,
label: "市场推广团队",
},
],
},
{
id: 4,
label: "人力资源部",
children: [
{
id: 9,
label: "招聘团队",
},
{
id: 10,
label: "培训团队",
},
],
},
],
},
],
};
},
created() {},
methods: {
deptExpandChange(options, val) {
this.$nextTick(() => {
// 兼容多个部门cascader时
let deptPopperContainers = document.querySelectorAll(
"body > .deptPopperContainer"
);
let el = deptPopperContainers[deptPopperContainers.length - 1];
let menuList = el.querySelectorAll(".deptPopperContainer .el-cascader-menu");
let clickIndex = val.length - 1;
let operatorIndex = val.length;
let offsetY = 30;
// 计算单个偏移量
let list = options;
let count = 0;
// 深度
for (let i = 0; i < operatorIndex; i++) {
// 广度
for (let j = 0; j < list.length; j++) {
if (list[j].id == val[i]) {
count = j;
break;
}
}
list = list[count].children;
}
count = count > 5 ? 5 : count;
// 计算上一次偏移量
let lastOffset = 0;
if (menuList[clickIndex].style.transform) {
lastOffset = parseInt(menuList[clickIndex].style.transform.slice(11));
}
if (menuList[operatorIndex]) {
menuList[operatorIndex].style.transform = `translateY(${
count * offsetY + lastOffset
}px)`;
}
});
},
},
};
</script>
<style lang="scss">
// 部门级联选择
.deptPopperContainer {
border: none;
box-shadow: none;
background: transparent;
.el-cascader-panel {
gap: 0 1px;
border: none;
box-shadow: none;
background: transparent;
}
.el-cascader-menu {
background: #ffffff;
border: solid 1px #dfe4ed;
border-radius: 4px;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
}
</style>