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

ExtJs 6.7.0 TreePanel锁定列时rowWidget展开错位问题求解

问题现象
  • 为搭载Ext.grid.Panel类型rowWidget的Ext.tree.Panel首列配置locked: true锁定属性后,触发rowWidget展开时无法同步撑开锁定列区域,出现行内容错位问题。
  • 开启列锁定功能后,树/表格组件会拆分为两个同步联动的网格,分别承载锁定列、非锁定列内容,默认逻辑下rowWidget的展开动作仅作用于非锁定列区域,未同步生效到锁定列侧。
  • 移除首列的locked: true配置后,组件rowWidget展开、收起逻辑运行正常,无错位问题。
问题根因

Ext JS锁定列的底层实现是将原面板拆分为两个独立的网格实例:lockedGrid承载锁定列内容,normalGrid承载非锁定列内容。二者默认仅同步滚动、行选中这类基础交互,未绑定rowWidget的展开状态、行高同步逻辑。
rowWidget触发展开时,只会在所属网格内生成widget组件、更新对应行高,另一侧网格既不会生成对应widget实例,也不会同步更新行高,最终两侧行高不匹配,触发内容错位。

修复方案

通过扩展树面板逻辑,绑定两侧网格的rowWidget状态同步即可解决问题,核心实现逻辑:

  1. 面板渲染完成后,校验是否存在锁定列拆分的双网格结构,仅在开启锁定列时启用同步逻辑
  2. 增加同步锁标记,避免双向事件监听触发死循环
  3. 同时监听两侧网格的expandbody、collapsebody事件,任意一侧触发展开/收起时,同步调用另一侧对应记录行的展开/收起方法
  4. 展开/收起过程中同步两侧对应行的高度,消除高度差导致的错位

核心实现代码:

Ext.define('Ext.ux.fix.LockedTreeRowWidgetSync', {
    override: 'Ext.tree.Panel',
    initComponent: function () {
        this.callParent(arguments);
        this.on('afterrender', this._bindRowWidgetSync, this, {single: true});
    },
    _bindRowWidgetSync: function () {
        const lockedGrid = this.lockedGrid,
            normalGrid = this.normalGrid;
        // 未开启锁定列时无需绑定
        if (!lockedGrid || !normalGrid) return;

        let syncFlag = false;
        const syncAction = (sourceGrid, record, isExpand, sourceRow) => {
            if (syncFlag) return;
            syncFlag = true;
            const targetGrid = sourceGrid === lockedGrid ? normalGrid : lockedGrid,
                targetView = targetGrid.getView(),
                targetRow = targetView.getRow(record);
            
            if (targetRow) {
                const isTargetExpanded = targetRow.classList.contains('x-grid-row-expanded');
                // 状态不一致时同步展开/收起
                if (isExpand !== isTargetExpanded) {
                    targetView.toggleRowExpansion(record, isExpand);
                }
                // 同步行高
                targetRow.style.height = isExpand ? `${sourceRow.offsetHeight}px` : '';
            }
            syncFlag = false;
        };

        // 给两侧网格绑定事件
        [lockedGrid, normalGrid].forEach(grid => {
            const view = grid.getView();
            view.on('expandbody', (rowNode, record) => {
                syncAction(grid, record, true, rowNode);
            });
            view.on('collapsebody', (rowNode, record) => {
                syncAction(grid, record, false, rowNode);
            });
        });
    }
});

补充说明:如果rowWidget内部承载交互类组件(表单、按钮组等),需要额外增加两侧widget实例的数据同步逻辑,避免同一条记录对应的两个widget实例数据状态不一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 02:57:08