Vue3+Ts+Element Plus 权限菜单控制节点

实现了完整的父子节点联动逻辑功能:

  1. 选择父节点时自动选中所有子节点
  2. 取消父节点时自动取消所有子节点
  3. 选择子节点时自动选中所有父节点
  4. 取消子节点时保留父节点的勾选状态

如图效果:

代码部分:

复制代码
<template>
  <div>
    <el-drawer
      v-model="dialogVisible"
      title="菜单权限设置 - 静态案例"
      size="400"
      @close="handleClose"
      class="pl-8 pr-8"
    >
      <div class="mb-4 text-sm text-gray-500">
        这是一个静态案例,展示父子节点联动选择功能
      </div>
      <el-tree
        ref="treeRef"
        :data="menuData"
        highlight-current
        show-checkbox
        :check-strictly="true"
        node-key="id"
        :default-checked-keys="defaultCheckedKeys"
        :props="defaultProps"
        :default-expand-all="true"
        @check="hanleCheck"
        @check-change="checkChange"
      />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleClose">取消</el-button>
          <el-button type="primary" @click="submitForm">确认</el-button>
        </div>
      </template>
    </el-drawer>
  </div>
</template>
逻辑部分:
复制代码
<script lang="ts" setup>
import { ElMessage } from "element-plus";
import { ref } from "vue";

// 类型定义
interface MenuItem {
  id: number;
  title: string;
  children?: MenuItem[];
}

interface FormInfo {
  menuIds: number[];
}

interface RowList {
  id?: number;
  menus_ids?: number[];
}

// 静态菜单数据
const menuData: MenuItem[] = [
  {
    id: 1,
    title: "系统管理",
    children: [
      { id: 11, title: "用户管理" },
      { id: 12, title: "角色管理" },
      { id: 13, title: "权限设置" }
    ]
  },
  {
    id: 2,
    title: "商品管理",
    children: [
      { id: 21, title: "商品列表" },
      { id: 22, title: "商品分类" },
      { id: 23, title: "库存管理" }
    ]
  },
  {
    id: 3,
    title: "订单管理",
    children: [
      { id: 31, title: "订单列表" },
      { id: 32, title: "退款管理" },
      { id: 33, title: "物流跟踪" }
    ]
  },
  {
    id: 4,
    title: "数据统计",
    children: [
      { id: 41, title: "销售统计" },
      { id: 42, title: "用户分析" },
      { id: 43, title: "商品分析" }
    ]
  }
];

// 默认选中的菜单ID
const defaultCheckedKeys = [11, 21, 31];

// 响应式数据
const dialogVisible = ref<boolean>(true);
const treeRef = ref();
const selectedMenuIds = ref<number[]>(defaultCheckedKeys);

const defaultProps = {
  children: "children",
  label: "title",
};

// 递归设置子节点的选择状态
const setChildrenChecked = (children: any[], isChecked: boolean) => {
  children.forEach((child: any) => {
    treeRef.value!.setChecked(child.id, isChecked, false);
    if (child.children && child.children.length > 0) {
      setChildrenChecked(child.children, isChecked);
    }
  });
};

// 递归选中所有父节点
const setParentChecked = (node: any) => {
  if (!node.parent) return;
  
  // 选中父节点
  treeRef.value!.setChecked(node.parent, true, false);
  
  // 继续递归选中父节点的父节点
  setParentChecked(node.parent);
};

// 处理节点选择
const hanleCheck = (data: MenuItem) => {
  const isChecked = treeRef.value!.getNode(data).checked;
  const currentNode = treeRef.value!.getNode(data);
  
  if (isChecked) {
    setParentChecked(currentNode);
    if (data.children?.length) {
      setChildrenChecked(data.children, true);
    }
  } else {
    if (data.children?.length && !currentNode.checked) {
      setChildrenChecked(data.children, false);
    }
  }
  
  updateSelectedMenuIds();
};

const checkChange = () => {
  updateSelectedMenuIds();
};

const updateSelectedMenuIds = () => {
  const checkedNodes = treeRef.value!.getCheckedNodes(false, false);
  selectedMenuIds.value = checkedNodes.map(node => node.id);
};

const handleClose = () => {
  dialogVisible.value = false;
  ElMessage.info("已关闭菜单权限设置");
};

const submitForm = () => {
  updateSelectedMenuIds();
  ElMessage.success(`权限设置成功!选中的菜单ID: [${selectedMenuIds.value.join(', ')}]`);
  console.log("选中的菜单ID:", selectedMenuIds.value);
};
</script>

<style scoped>
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 16px;
}
</style>
相关推荐
Z***u6599 分钟前
前端性能测试实践
前端
xhxxx13 分钟前
prototype 是遗产,proto 是族谱:一文吃透 JS 原型链
前端·javascript
倾墨14 分钟前
Bytebot源码学习
前端
用户938169125536017 分钟前
VUE3项目--集成Sass
前端
S***H28327 分钟前
Vue语音识别案例
前端·vue.js·语音识别
涔溪1 小时前
通过Nginx反向代理配置连接多个后端服务器
vue.js·nginx
啦啦9118861 小时前
【版本更新】Edge 浏览器 v142.0.3595.94 绿色增强版+官方安装包
前端·edge
蚂蚁集团数据体验技术1 小时前
一个可以补充 Mermaid 的可视化组件库 Infographic
前端·javascript·llm
LQW_home2 小时前
前端展示 接受springboot Flux数据demo
前端·css·css3
q***d1732 小时前
前端增强现实案例
前端·ar