vue3权限树组件
功能:
1、勾选节点、自动把父节点勾选。
2、取消勾选、子节点全部取消勾选。检查父节点,如果只有这个子节点、遍历把父节点取消勾选
3、filter过滤不仅展示父节点、相关子节点同时展示
4、 高亮显示所有过滤数据
效果图

父组件引用
<template>
<Tree ref="treeRef" :data="data" style="width: 100%;"/>
</template>
<script setup lang="ts">
import Tree from './tree.vue'
const data = ref([])
//1. 设置选中节点
const taskCodes = res.data.permissionList.map(item => item.taskCode);
treeRef.value!.setCheckedKeys(taskCodes);
// 2. 获取选中的节点
permissionList.value = treeRef.value!.getPermissionList()
</script>
tree子组件
<template>
<span>
<el-input v-model="filterText" class="w-60 mb-2" placeholder="请输入菜单名称" />
<el-tree style="width: 100%;height: calc(100vh - 370px);overflow-y: auto;" :data="data" ref="treeRef"
:props="defaultProps" node-key="id" default-expand-all :expand-on-click-node="false" :check-strictly="true"
show-checkbox @check-change="handleCheckChange" @node-click="handleNodeClick"
:filter-node-method="filterNode"
:render-content="renderNode"
/>
</span>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, defineExpose } from 'vue'
import { useVModels } from "@vueuse/core";
const treeRef = ref()
const filterText = ref('')
const props = defineProps<{
data: any;
}>();
const emit = defineEmits(["update:data"]);
const { data } = useVModels(props, emit);
const defaultProps = {
children: 'children',
label: 'label',
disabled: 'disabled',
}
const handleCheckChange = (node, checked, indeterminate) => {
if (checked) {
ensureParentChecked(node);
}
else {
checkParentUncheck(node);
// 子级节点取消勾选
checkChildUncheck(node);
}
}
const handleNodeClick = (node, checked) => {
if (!checked.checked) {
ensureParentChecked(node);
}
else {
checkParentUncheck(node);
// 子级节点取消勾选
checkChildUncheck(node);
}
}
const ensureParentChecked = (node) => {
treeRef.value!.setChecked(node, true, false);
const parent = treeRef.value!.getNode(node)?.parent;
if (parent && parent.data) {
treeRef.value!.setChecked(parent.data, true, false);
ensureParentChecked(parent.data);
}
}
const checkParentUncheck = (node) => {
treeRef.value!.setChecked(node, false, false);
const parent = treeRef.value!.getNode(node)?.parent;
if (!parent || !parent.data) return;
const children = parent.childNodes;
const allUnchecked = children.every(child => {
return !child.checked && !child.indeterminate;
});
if (allUnchecked) {
treeRef.value!.setChecked(parent.data, false, false);
checkParentUncheck(parent.data);
}
}
const checkChildUncheck = (node) => {
const children = treeRef.value!.getNode(node)?.childNodes;
if (children) {
children.forEach(child => {
treeRef.value!.setChecked(child, false, false);
checkChildUncheck(child);
});
}
}
const filterNode = (value: string, data: any, node: any) => {
if (!value) return true
let _array = [];//这里使用数组存储 只是为了存储值。
getReturnNode(node, _array, value);
let result = false;
_array.forEach((item) => {
result = result || item;
});
return result;
}
const getReturnNode = (node, _array, value) =>{
let isPass = node.data && node.data.label && node.data.label.indexOf(value) !== -1;
isPass ? _array.push(isPass) : '';
if (!isPass && node.level != 1 && node.parent) {
getReturnNode(node.parent, _array, value);
}
}
// 自定义节点渲染函数
const renderNode = (h: any, { node, data }: any) => {
const label = data.label;
const filterValue = filterText.value;
if (filterValue && label.includes(filterValue)) {
const parts = label.split(new RegExp(`(${filterValue})`, 'gi'));
return h('span', {}, parts.map(part => {
if (part.toLowerCase() === filterValue.toLowerCase()) {
return h('span', { style: { color: 'red' } }, part);
}
return h('span', part);
}));
}
return h('span', label);
};
watch(filterText, (val) => {
treeRef.value!.filter(val)
})
const getPermissionList = () => {
return treeRef.value!.getCheckedNodes().map((item: { id: string; label: string }) => ({
taskCode: item.id,
taskName: item.label
}));
}
const setCheckedKeys = (keys: string[]) => {
treeRef.value!.setCheckedKeys(keys, false);
}
defineExpose({
getPermissionList, // 获取选中的权限列表
setCheckedKeys, // 设置选中的权限列表
})
</script>
1872

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



