el-cascader级联偏移效果

问题描述

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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值