menuTree.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <script setup lang="ts">
  2. import {onMounted, ref, defineEmits, watch, nextTick} from "vue";
  3. import {getMenuListTree} from "@/api/system/menu";
  4. import {type CheckboxValueType} from 'element-plus'
  5. onMounted(() => {
  6. getMenuList();
  7. console.log(model.value)
  8. })
  9. const emit = defineEmits(['update:modelValue'])
  10. const menuList = ref([]);
  11. const getMenuList = async () => {
  12. let res = await getMenuListTree();
  13. menuList.value = res.data;
  14. }
  15. const model = defineModel()
  16. watch(model, (value: number[]) => {
  17. nextTick(() => {
  18. setCheckedKeys(value, true)
  19. const allKeys = getAllKeys(menuList.value);
  20. menuNodeAll.value = value.length === allKeys.length;
  21. isIndeterminate.value = value.length > 0 && value.length < allKeys.length;
  22. })
  23. }, {immediate: true, deep: true})
  24. const menuRef = ref(null)
  25. const menuCheckStrictly = ref(true)
  26. const menuNodeAll = ref(false)
  27. const menuExpand = ref(false)
  28. const isIndeterminate = ref(false)
  29. const handleCheckedTreeExpand = (value: CheckboxValueType) => {
  30. // 递归展开
  31. for (let i = 0; i < menuList.value.length; i++) {
  32. menuRef.value.store.nodesMap[menuList.value[i].id].expanded = value;
  33. }
  34. }
  35. const handleCheckedTreeNodeAll = (value: CheckboxValueType) => {
  36. menuRef.value.setCheckedNodes(value ? menuList.value : []);
  37. isIndeterminate.value = false;
  38. const allKeys = getAllKeys(menuList.value);
  39. model.value = value ? allKeys : [];
  40. console.log(model.value)
  41. console.log(menuNodeAll.value)
  42. }
  43. const handleTreeCheck = (_: any, checkedState: any) => {
  44. const allKeys = getAllKeys(menuList.value);
  45. const checkedCount = checkedState.checkedKeys.length;
  46. menuNodeAll.value = checkedCount === allKeys.length;
  47. isIndeterminate.value = checkedCount > 0 && checkedCount < allKeys.length;
  48. model.value = checkedState.checkedKeys
  49. emit("update:modelValue", checkedState.checkedKeys)
  50. }
  51. // 递归获取所有节点key
  52. const getAllKeys = (data: any) => {
  53. return data.reduce((keys: any, node: any) => {
  54. keys.push(node.id);
  55. if (node.children && menuCheckStrictly) {
  56. keys.push(...getAllKeys(node.children));
  57. }
  58. return keys;
  59. }, []);
  60. }
  61. const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
  62. return menuRef.value.setCheckedKeys(keys, leafOnly)
  63. }
  64. </script>
  65. <template>
  66. <div style="width: 100%">
  67. <el-row type="flex" justify="space-between" align="middle">
  68. <el-col :span="4">
  69. <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event)">全部展开/折叠
  70. </el-checkbox>
  71. </el-col>
  72. <el-col :span="4">
  73. <el-checkbox :indeterminate="isIndeterminate" v-model="menuNodeAll"
  74. @change="handleCheckedTreeNodeAll($event)">全选/全不选
  75. </el-checkbox>
  76. </el-col>
  77. <el-col :span="4">
  78. <el-checkbox v-model="menuCheckStrictly">级联下级
  79. </el-checkbox>
  80. </el-col>
  81. </el-row>
  82. <el-tree class="tree-border" :data="menuList" show-checkbox ref="menuRef" node-key="id"
  83. empty-text="加载中,请稍后"
  84. :check-strictly="!menuCheckStrictly" @check="handleTreeCheck">
  85. </el-tree>
  86. </div>
  87. </template>
  88. <style scoped lang="scss">
  89. /* tree border */
  90. .tree-border {
  91. width: 100%;
  92. margin-top: 5px;
  93. border: 1px solid #e5e6e7;
  94. background: #FFFFFF none;
  95. border-radius: 4px;
  96. }
  97. </style>