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 truelet _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>