关于javascript:原生跨框架的表格组件三步实现万条不卡

37次阅读

共计 2362 个字符,预计需要花费 6 分钟才能阅读完成。

确定在 GridManager 内实现万条不卡的想法,最早呈现于 2021 年初同 郑某人 杨某人 的饭局上。现在性能曾经实现,整顿下这个值得记录的过程。

现状剖析

在虚构滚动落地前,针对于现有逻辑的革新是个前置条件。

上方 gif 内演示了在实现万条不卡前,表格组件所领有的局部能力。因为这些能力搭建于原生跨框架的构造上,所以在须要对渲染逻辑进行较大范畴革新时,原先的能力就成为了不小的包袱。

因而在不影响现有性能的状况下反对万条不卡,须要按序实现以下三个步骤:

  • tbody 区域的数据驱动革新: 升高性能复杂度
  • 差异化更新: 缩小 DOM 节点的更新频率
  • 虚构滚动: 缩小 DOM 节点的更新数量

三个步骤

基于数据驱动,构建差异化更新,最终实现虚构滚动。

1、数据驱动

随着 js 框架的呈现,数据驱动扭转了前端组件的渲染逻辑。

对于一个脱离框架的原生表格组件,尽管须要自行实现数据驱动,但难度其实不大,只需将 tbody 区域内的所有渲染逻辑进行整合,并向外透出惟一的数据变更接管函数。

这个函数起到一个承前启后的作用,隔离了数据层与视图层。在数据变更时被触发,并依据触发的不同场景对 tbody 区域进行渲染。

假如这个函数叫changeTableData,实现数据驱动后的逻辑如下:

// 当数据变更时,函数会被触发,由该函数来判断哪些 DOM 应该被更新。changeTableData() {const data = getTableData();
    // tbody render
    renderTbody(data);
}


// 场景一: 分页被执行时
changeTableData();

// 场景二: 某条数据被批改时
changeTableData();

数据驱动只是一个先决条件,差异化更新和虚构滚动才是解决卡顿的伎俩。

2、差异化更新

表格组件所依赖的数据无论是什么格局,都会存在一个与渲染后果相匹配的数组。

[{
    id: 1,
    name: '张三'
},{
    id: 2,
    name: '李四'
},{
    id: 3,
    name: '王五'
}]

这个数组在特定状况下,返回后果会存在与已渲染数据雷同或局部雷同的状况。比如说: 在触发搜寻后再次返回了以下数据:

[{
    id: 1,
    name: '张三丰'
},{
    id: 2,
    name: '李四'
},{
    id: 3,
    name: '王五'
},{
    id: 4,
    name: '赵六'
}]

将两次的返回后果进行比拟,能够发现:

  • 数组的长度减少 1
  • 索引为 0 的 name 产生了变动

如果不加甄别的进行从新渲染,就会存在不必要的 DOM 操作,特地是在数据量较大时,对性能的耗费是极大的。
为避免不必要的性能耗费,须要基于数据驱动的逻辑对 DOM 进行差异化更新。

const diffTableData = (oldData, newData) => {
    // 通过比对 oldData 与 newData,生成一个新的数组
    const diffList = [];
    // ... 省略掉的比对逻辑
    return diffList;
};

通过 diffTableData 函数,比对数据失去以下后果:

[{
    id: 1,
    name: '张三丰'
},
,
,
{
    id: 4,
    name: '赵六'
}]

在失去排重的后果后,并数据进行渲染。

changeTableData() {const oldData = getOldData();
    const newData = getNewData();
    // 提供 diff 函数,将比对后的数据进行渲染,未变更的 DOM 不更新
    const diffData = diffTableData(oldData, newData);
    // tbody render
    renderTbody(diffData);
}

以上示例仅是用于展现逻辑,残缺实现可点击 github 地址查看 diffTableData 函数。

3、虚构滚动

用户看到的一万条数据,其实在前端只渲染了 20 条。

当原生表格的 tbody 区域实现数据驱动后,通过在 changeTableData 中提供勾子供 scroll 事件调用即可实现虚构滚动。

在勾子内通过滚轴的 scrollTop 计算以后须要显示的数据,通过 margin 填充虚构局部的滚轴高度。并在这些根底上减少一些防抖机制,让虚构滚动更晦涩。

changeTableData() {
    // 在 tbody 区域滚轴事件中调用
    virtualScrollMap[key] = () => {
        // 1、计算以后须要显示的数据,保障 tr 的最大值不超过 20
        // 2、通过 margin 填充虚构局部的滚轴高度
        // 3、减少防抖
    };
}

// tbody 区域的滚轴事件
onScroll = () => {
    // 调用 changeTableData 提供的勾子
    virtualScrollMap[key]();}

以上示例仅是用于展现逻辑,残缺实现可点击 github 地址查点 changeTableData 函数。

成果展现

tbody 区域实现 数据驱动 差异化更新 虚构滚动 后,在 2021 年的最初一天,万条不卡最终以即定步骤得以公布,成果如下:

new GridManager(table, {
    // 启用虚构滚动 @2.18.0
    virtualScroll: {
    // 在应用 supportTreeData 与 fullColumn 时虚构滚动有效。// 应用动态导出,必须配置 handler,否则导出数据长度为 virtualNum;// 打印时仅对以后配置 virtualNum 的条数失效
    useVirtualScroll: true,

    // 理论渲染的 Tr 数,该数值大于当前页数据长度时,虚构滚动不失效
    virtualNum: 10
    },
    // ... 其它配置项
});

gif 中能够看出,尽管存在 10000 条数据,但 tbody 区域的 tr 节点始终放弃在 10 个。table 上的 margin 依据滚动轴的地位一直变动,撑持着表格区域的高度。

开源不易

最近听 杨某人 说要搞个组件库,闲聊间想起六年前 GridManager 的样子,真是一言难尽、一路艰苦。

开源不易,心愿能够坚持下去。

正文完
 0