You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript实现jQuery递归树形结构生成性能优化求助

优化Tree节点渲染性能的解决方案

问题分析

从你的代码来看,处理413个3层级节点耗时超2秒,核心瓶颈在于频繁的DOM操作和重复编译Handlebars模板:

  • 每次递归都直接将新创建的DOM节点append到页面,触发多次重排重绘;
  • 每个节点渲染时都重新编译Handlebars模板,这是不必要的性能开销;
  • 大量使用JQuery的$()创建单个元素,多次append操作累积了额外的性能成本。

优化方案

下面是针对性的优化代码,核心思路是:离线构建HTML内容,一次性插入DOM;预编译Handlebars模板,避免重复编译;减少JQuery的频繁调用。

优化后的TypeScript代码

// 预编译Handlebars模板,只执行一次
let compiledTemplate: HandlebarsTemplateDelegate | null = null;

static createParentNodes($tree: JQuery, $nodeContainer: JQuery, nodes: any, settings: any) {
    // 预编译模板,避免重复编译
    if (!compiledTemplate) {
        let textTemplate = settings?.textTemplate || $tree.data("textTemplate") || "";
        compiledTemplate = Handlebars.compile(textTemplate);
    }

    // 使用DocumentFragment离线构建DOM,避免频繁重排
    const fragment = document.createDocumentFragment();
    const $ul = $('<ul></ul>')[0];

    nodes.forEach((nodeData: any) => {
        const liHtml = gmTree.buildLiNodeHtml($tree, nodeData, settings, compiledTemplate);
        $ul.innerHTML += liHtml;
    });

    fragment.appendChild($ul);
    $nodeContainer.append(fragment);
}

static buildLiNodeHtml($tree: JQuery, data: any, settings: any, template: HandlebarsTemplateDelegate): string {
    const treeId = $tree.attr("id") || "";
    const checkboxId = `chk_${data.id}`;
    const finalData = data.data || data;
    const displayContent = template(finalData);

    // 构建基础Li的HTML字符串
    let liHtml = `<li class="treeLi" data-id="${data.id}" data-nodeData='${JSON.stringify(data)}'`;
    if (settings?.parentId) {
        liHtml += ` data-parentId="${settings.parentId}"`;
    }
    liHtml += `>`;

    // 构建节点内容区域
    liHtml += `<div class="tree-li-data">`;
    // 处理展开器和复选框的显示状态
    const expanderClass = data.children?.length > 0 ? "" : "hidden";
    liHtml += `<span class="${expanderClass}" data-role="tree-expander"><i class="material-icons">add</i></span>`;
    
    const checkboxClass = data.children?.length > 0 ? "hidden" : "";
    liHtml += `<span class="${checkboxClass}" data-role="tree-checkbox"><input type="checkbox" id="${checkboxId}" class="chk-col-blue"/><label for="${checkboxId}"></label></span>`;
    
    liHtml += `<span data-role="tree-display" id="${treeId}Dis${data.id}">${displayContent}</span>`;
    liHtml += `</div>`;

    // 递归构建子节点的HTML
    if (data.children?.length > 0) {
        liHtml += `<ul>`;
        data.children.forEach((child: any) => {
            liHtml += gmTree.buildLiNodeHtml($tree, child, { parentId: data.id }, template);
        });
        liHtml += `</ul>`;
    }

    liHtml += `</li>`;
    return liHtml;
}

// 插入DOM后再统一绑定数据和触发事件
static initTreeNodes($tree: JQuery) {
    $tree.find('.treeLi').each(function() {
        const $li = $(this);
        const nodeData = JSON.parse($li.data('nodeData') as string);
        const $parent = $li.closest('li');
        
        $li.data("parent", $parent);
        $li.data("objectData", nodeData);
        $li.trigger(ON_NODE_CREATED, { data: nodeData.data || nodeData });
    });
}

优化点说明

  1. 预编译Handlebars模板:模板只编译一次,所有节点共享编译后的函数,避免了重复编译的开销;
  2. 离线构建HTML字符串:通过字符串拼接生成所有节点的HTML,最后一次性插入到DocumentFragment,再添加到DOM,大幅减少重排重绘次数;
  3. 减少JQuery调用:避免了每次创建单个JQuery元素的开销,改用原生DOM的DocumentFragment和innerHTML来批量处理;
  4. 延迟数据绑定和事件触发:所有节点插入DOM后再统一绑定数据和触发ON_NODE_CREATED事件,减少零散操作的性能消耗。

使用方式

调用时先构建整个树的HTML,再初始化节点数据和事件:

// 假设获取到nodes数据源后
gmTree.createParentNodes($tree, $nodeContainer, nodes, settings);
gmTree.initTreeNodes($tree);

这样处理后,400+节点的渲染耗时应该能降到几百毫秒以内,显著提升性能。

内容的提问来源于stack exchange,提问作者Bahman Shafiei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:33:05