el-cascader实现左侧多选,右侧单选

最近有需求要让在设置角色在多个系统中的角色,但每个系统只能选择一种角色,细节说就是级联选框左侧是不同的系统,右侧项目对应的角色身份,而分配权限每个项目只能选择一个角色。
查阅了文档发现没有配置项,网上的很多方法也比较老旧,而且大部分不够匹配我遇到的情况,于是自己开始研究,代码如下:

<el-cascader
  v-model="accountData.role"
  :options="projectRoleOptions"
  :props="{ multiple: true }"
  collapse-tags
  collapse-tags-tooltip
  placeholder="Please select the role"
  style="width: 414px;"
  popper-class="user-cascader"
/>
watch(
  () => accountData.value.role,
  async (newVal) => {
    const val = newVal.reduce((acc, subArray) => {
      const [key, value] = subArray
      if (!acc[key]) {
          acc[key] = []
      }
      acc[key].push(value)
      return acc
    }, {})
    projectRoleOptions.value.forEach((category) => {
      category.children.forEach((option) => {
        if (isArray(val[category.value])) {
          option.disabled = !val[category.value].toString().includes(option.value)
        } else if (val[category.value] == undefined || val[category.value].length == 0) {
          option.disabled = false
        }
      });
    });
    await nextTick()
    restoreScrollPosition();
  },
  { deep: true }
);

以上是主要核心代码,最后实现的功能效果是正常的,主要的逻辑就是在每次数据改变的时候,拿到第一层节点对应的第二层节点,如果存在有选中的某一项,那么将其他项置为disabled,如果都没有被选择,则将他们的disabled置为false(业务功能目标)。但是实现后存在有一个问题,当左侧的滚动列表比较低出现滚动条时,那么这时再去进行选择左侧的滚动条会回到最顶端,推测是由于整个列表被重新赋值导致的。
为了解决这个问题,在这之后我尝试了很多方案,比如进行computed缓存,nexttick之后进行更新,将目标对象进行拷贝后再重新赋值,但都无果,至少是我自己这边是无效的。因此最后我决定在数据修改后将滚动的位置恢复,以下是代码实现:

const savedScrollPosition = ref(0); // 保存滚动位置
const cascaderMenuRef = ref(null); // 引用 Cascader 菜单

// 获取滚动条位置的函数
const handleScroll = () => {
  if (cascaderMenuRef.value) {
    savedScrollPosition.value = cascaderMenuRef.value.scrollTop;
  }
};

// 在 DOM 更新后恢复滚动位置
const restoreScrollPosition = () => {
  if (cascaderMenuRef.value) {
    nextTick(() => {
      cascaderMenuRef.value.scrollTop = savedScrollPosition.value;
    })
  }
};

watch(
  () => accountData.value.role,
  async (newVal) => {
    const val = newVal.reduce((acc, subArray) => {
      const [key, value] = subArray
      if (!acc[key]) {
          acc[key] = []
      }
      acc[key].push(value)
      return acc
    }, {})
    projectRoleOptions.value.forEach((category) => {
      category.children.forEach((option) => {
        if (isArray(val[category.value])) {
          option.disabled = !val[category.value].toString().includes(option.value)
        } else if (val[category.value] == undefined || val[category.value].length == 0) {
          option.disabled = false
        }
      });
    });
    await nextTick()
    restoreScrollPosition();
  },
  { deep: true }
);

// 监听滚动事件并保存滚动位置
onMounted(() => {
  cascaderMenuRef.value = document.querySelector('.user-cascader .el-cascader-menu .el-cascader-menu__wrap');
  if (cascaderMenuRef.value) {
    cascaderMenuRef.value.addEventListener('scroll', handleScroll);
  }
});
onBeforeUnmount(() => {
  if (cascaderMenuRef.value) {
    cascaderMenuRef.value.removeEventListener('scroll', handleScroll);
  }
});

最终实现了我想要的效果
参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值