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>
相关推荐
FIN66684 小时前
昂瑞微:以射频“芯”火 点亮科技强国之路
前端·人工智能·科技·前端框架·智能
携欢4 小时前
PortSwigger靶场之Exploiting server-side parameter pollution in a REST URL通关秘籍
前端·javascript·安全
鹏多多4 小时前
今天你就是VS Code之神!15个隐藏技巧让代码效率翻倍
前端·程序员·visual studio code
linksinke4 小时前
html案例:制作一个图片水印生成器,防止复印件被滥用
开发语言·前端·程序人生·html
寒月霜华4 小时前
JavaWeb-html、css-网页正文制作
前端·css·html
执沐4 小时前
HTML实现流星雨
前端·html
*濒危物种*4 小时前
HTML标签语法,基本框架
前端·css·html
软件技术NINI4 小时前
html css js网页制作成品——HTML+CSS+js早餐铺网页设计(4页)附源码
javascript·css·html
IT_陈寒4 小时前
Vue3性能优化实战:这7个技巧让我的应用提速50%,尤雨溪都点赞!
前端·人工智能·后端