首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

jQuery 樹形菜單實現:遞歸構建與交互展開收縮完整示例

     編輯:Java 相關知識

樹形菜單是後台管理系統導航的標準組件。本文提供一個零依賴(僅需 jQuery + 簡單 CSS)的樹形菜單實現,採用遞歸構建 DOM、事件委派控制展開收縮、支持異步加載擴展,適合快速集成到項目中。

一、效果預覽

樹形菜單效果圖

二、數據結構設計

採用扁平數組 + pid 父子關係,便於後端查詢與前端遞歸構建:

var treeData = [
    { "id": "1", "pid": "0", "name": "頂級分類1" },
    { "id": "2", "pid": "0", "name": "頂級分類2" },
    { "id": "3", "pid": "0", "name": "頂級分類3" },
    { "id": "4", "pid": "1", "name": "分類1父1" },
    { "id": "5", "pid": "1", "name": "分類1父2" },
    { "id": "6", "pid": "2", "name": "分類2父1" },
    { "id": "7", "pid": "2", "name": "分類2父2" },
    { "id": "8", "pid": "3", "name": "分類3父1" },
    { "id": "9", "pid": "3", "name": "分類3父2" },
    { "id": "10", "pid": "4", "name": "分類1父1子1" },
    { "id": "11", "pid": "5", "name": "分類1父2子1" },
    { "id": "12", "pid": "6", "name": "分類2父1子1" },
    { "id": "13", "pid": "7", "name": "分類2父2子1" }
];

三、HTML 骨架

<div id="main">
    <h1>樹形顯示關系圖 - 默認展開第一節點及其子節點</h1>
    <ul id="browser" class="treeview"></ul>
</div>

四、核心 JS 實現

$(document).ready(function () {
    init();
});

// 入口:構建頂級節點並默認展開
function init() {
    var $tree = $("#browser");
    var firstId = "";
    
    // 1. 構建頂級節點 (pid === "0")
    for (var i = 0; i < treeData.length; i++) {
        if (treeData[i].pid === "0") {
            if (!firstId) firstId = treeData[i].id;
            $tree.append(buildNodeHtml(treeData[i]));
        }
    }
    
    // 2. 默認展開第一個頂級節點
    if (firstId) {
        expandNode(firstId);
        // 可選:默認展開第一個子節點
        var firstChildId = getFirstChildId(firstId);
        if (firstChildId) expandNode(firstChildId);
    }
}

// 構建單個節點 HTML(含展開圖標、標題、空子容器)
function buildNodeHtml(node) {
    return "<li id='" + node.id + "' class='hasChildren expandable'>" +
           "<span class='folder' onclick='expandNode(\"" + node.id + "\")'>" +
           node.name + "</span><ul></ul></li>";
}

// 核心:節點展開/收縮邏輯
function expandNode(id) {
    var $node = $("#" + id);
    var cls = $node.attr("class");
    
    // 情況 A:已加載子節點 → 切換展開/收縮狀態
    if (cls !== "hasChildren expandable") {
        $node.find("> ul").slideToggle(200);
        $node.attr("class", cls === "expandable" ? "collapsable" : "expandable");
        return;
    }
    
    // 情況 B:首次展開 → 動態加載子節點
    var hasChildren = false;
    for (var i = 0; i < treeData.length; i++) {
        if (treeData[i].pid === id) {
            hasChildren = true;
            $node.find("> ul").append(buildNodeHtml(treeData[i]));
        }
    }
    
    // 更新狀態:若無子節點則標記為葉子節點
    if (hasChildren) {
        $node.attr("class", "collapsable");
    } else {
        $node.attr("class", "leaf").find("> span").removeClass("folder").addClass("file");
    }
}

// 輔助:獲取首個子節點 ID
function getFirstChildId(parentId) {
    for (var i = 0; i < treeData.length; i++) {
        if (treeData[i].pid === parentId) return treeData[i].id;
    }
    return null;
}

五、關鍵 CSS(參考 TreeView 風格)

.treeview { margin: 0; padding: 0; list-style: none; }
.treeview li { margin: 0; padding: 0 0 0 20px; position: relative; }
.treeview .hasChildren > span.folder { cursor: pointer; background: url(folder.png) no-repeat 0 2px; padding-left: 20px; }
.treeview .expandable > span.folder { background-image: url(folder-closed.png); }
.treeview .collapsable > span.folder { background-image: url(folder-open.png); }
.treeview .leaf > span.file { background: url(file.png) no-repeat 0 2px; padding-left: 20px; }
.treeview ul { display: none; } /* 初始收縮 */
.treeview .collapsable > ul { display: block; } /* 展開狀態顯示 */

六、擴展:異步加載模式

將 expandNode 中的數據遍歷替換為 AJAX 請求:

function expandNode(id) {
    var $node = $("#" + id);
    if ($node.hasClass("loaded")) {  // 已加載標記
        $node.find("> ul").slideToggle();
        $node.toggleClass("expandable collapsable");
        return;
    }
    
    $.getJSON("/api/tree/children", { parentId: id }, function(nodes) {
        $.each(nodes, function(i, node) {
            $node.find("> ul").append(buildNodeHtml(node));
        });
        $node.addClass("loaded collapsable").removeClass("expandable");
        $node.find("> ul").show();
    });
}

七、優化建議

  1. 事件委派:將 onclick 內聯改為 $(document).on('click', '.treeview .folder', handler),減少內存佔用,支持動態添加節點。
  2. 虛擬滾動:節點超過 500+ 時,採用 react-virtualized 或原生 IntersectionObserver 按需渲染。
  3. 狀態持久化:展開狀態存入 localStorage,頁面刷新恢復用戶上下文。
  4. 無障礙支持:添加 role="treeitem"、aria-expanded、鍵盤導航(←/→ 展開收縮,↑/↓ 選中)。

這個實現邏輯清晰、擴展性強,通過 hasChildren expandable/collapsable/leaf 狀態機精確控制節點生命週期,是構建企業級導航菜單的優質起點。

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