首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

樹形菜單根據權限數據動態勾選:前後端數據結構設計與遞歸匹配實現

     編輯:程式設計綜合問答

業務場景

後端返回兩組數據:

  1. allMenus:完整菜單樹 (含 id、parentId、name、children...)
  2. userRights:用戶擁有的權限菜單 ID 集合 (如 [101, 103, 105])

前端需渲染樹形組件 (如 Element UI el-tree、zTree、Ant Design Tree),並自動勾選用戶擁有的節點。

後端返回結構建議

// 方案 A:兩個獨立列表 (原始回答思路)
{
  "allMenus": [{ "id": 1, "parentId": 0, "name": "系統管理", "children": [...] }],
  "userRightIds": [101, 103, 105]
}

// 方案 B:單樹節點內嵌權限標記 (前端更省事)
{
  "menuTree": [{
    "id": 1,
    "parentId": 0,
    "name": "系統管理",
    "checked": false,        // 當前用戶是否擁有
    "halfChecked": false,    // 子節點部分擁有
    "children": [...]
  }]
}

前端遞歸匹配核心邏輯 (方案 A)


// 假設使用 Vue + Element UI
export default {
  props: {
    allMenus: Array,
    userRightIds: Array
  },
  data() {
    return {
      defaultCheckedKeys: [], // 完全勾選的節點 id
      defaultExpandedKeys: [] // 默認展開的節點 id
    };
  },
  mounted() {
    this.initCheckedKeys(this.allMenus);
  },
  methods: {
    // 遞歸遍歷樹,收集用戶擁有的節點 id
    initCheckedKeys(nodes) {
      nodes.forEach(node => {
        if (this.userRightIds.includes(node.id)) {
          this.defaultCheckedKeys.push(node.id);
        }
        if (node.children?.length) {
          this.initCheckedKeys(node.children);
        }
      });
    }
  }
};

進階:父子節點聯動邏輯 (勾選父 → 全選子,全選子 → 勾選父)

若樹組件不支持原生聯動,需自行實現:


// 1. 父節點變化 → 遞歸設置所有後代
onParentCheck(node, checked) {
  this.setDescendantsChecked(node, checked);
},

// 2. 子節點變化 → 向上更新父節點狀態 (全選/半選/未選)
onChildCheck(node, checked) {
  this.updateAncestorsStatus(node.parentId);
},

// 3. 計算父節點狀態
updateAncestorsStatus(parentId) {
  const parent = this.findNode(parentId);
  if (!parent) return;
  
  const childIds = parent.children.map(c => c.id);
  const checkedCount = childIds.filter(id => this.defaultCheckedKeys.includes(id)).length;
  
  if (checkedCount === 0) {
    this.uncheckParent(parentId);
  } else if (checkedCount === childIds.length) {
    this.checkParent(parentId); // 遞歸向上
  } else {
    this.halfCheckParent(parentId); // 半選狀態
  }
}

後端優化建議

  • 權限 ID 集合用 Set<Long> 存儲,O(1) 判斷包含
  • 菜單樹構建採用 Map<Long, Node> + 一次遍歷掛載 children,避免遞歸查庫
  • 大量數據考慮分頁/懶加載:load(currentNode, resolve) 動態請求子節點

總結

「後端返回樹 + 權限 ID 扁平列表,前端遞歸匹配生成 checkedKeys」是最通用、解耦的方案。掌握樹形數據的遞歸遍歷與狀態同步,是前端必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved