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

被折叠的 条评论
为什么被折叠?



