当前位置: 首页 > Web前端 > HTML

原生跨框架表格组件,三步实现万无卡

时间:2023-03-27 23:17:46 HTML

在GridManager中实现万无卡的想法最早出现在2021年初郑、杨的晚宴上,现在功能已经实现,我们来梳理一下这个值得记录的过程。现状分析在实施虚拟滚动之前,改造现有逻辑是一个前提。上面的gif演示了表格组件在万无一失卡实现前的一些能力。由于这些能力是建立在原生的跨框架结构之上的,当需要对渲染逻辑进行大规模改造时,原有的能力就会成为很大的负担。因此,要在不影响现有功能的情况下支持上万张卡片,需要依次执行以下三个步骤:tbody区域的数据驱动改造:降低功能复杂度差异化更新:降低DOM节点的更新频率虚拟滚动:Reduce更新DOM节点数的三个步骤是基于数据驱动,构建差异化更新,最终实现虚拟滚动。1、数据驱动随着js框架的出现,数据驱动改变了前端组件的渲染逻辑。对于一个脱离框架的原生表格组件,虽然需要自己实现数据驱动,但并不难。只需要将tbody区域的所有渲染逻辑都整合起来,对外暴露唯一的数据变化接收函数即可。该功能起到承前启后的作用,隔离了数据层和视图层。数据变化时触发,根据不同的触发场景渲染tbody区域。假设这个函数叫做changeTableData,实现数据驱动后的逻辑如下:当数据发生变化时,会触发该函数,由该函数决定更新哪个DOM。changeTableData(){常量数据=getTableData();//tbodyrenderrenderTbody(data);}//场景一:执行分页时changeTableData();//场景二:修改一条数据时changeTableData();data驱动只是前提条件,差异更新和虚拟滚动才是解决问题的手段。2.不管表格组件依赖的数据是什么格式,更新方式不同,总会有一个数组匹配渲染结果。[{id:1,name:'张三'},{id:2,name:'李四'},{id:3,name:'王舞'}]在某些情况下,这个数组的返回结果会出现数据与渲染数据相同或部分相同的情况。例如:触发搜索后,再次返回如下数据:[{id:1,name:'张三丰'},{id:2,name:'李四'},{id:3,name:'WangWu'},{id:4,name:'赵刘'}]对比两次返回结果可以发现:数组长度增加了1,索引为0的name发生了变化。如果不经过筛选就重新渲染,将会有不必要的DOM操作,尤其是在数据量很大的时候,会消耗大量的性能。为了防止不必要的性能消耗,DOM需要根据数据驱动逻辑进行不同的更新。constdiffTableData=(oldData,newData)=>{//通过比较oldData和newData生成一个新数组constdiffList=[];//...省略的比较逻辑returndiffList;};通过diffTableData函数,对比数据得到如下结果:[{id:1,name:'张三丰'},,,{id:4,name:'赵六'}]得到权重排序结果后,渲染数据。changeTableData(){constoldData=getOldData();constnewData=getNewData();//提供一个diff函数来渲染比较数据,不变的DOM不会被更新constdiffData=diffTableData(oldData,newData);//tbodyrenderrenderTbody(diffData);}上面的例子只是用来展示逻辑。完整的实现可以点击github地址查看diffTableData函数。3、虚拟滚动用户看到的10000条数据,其实前端渲染的数据只有20条。nativetable的tbody区域数据驱动后,可以通过在changeTableData中提供一个hook供scroll事件调用来实现虚拟滚动。在hook中,通过滚轮的scrollTop计算当前要显示的数据,通过margin填充虚拟部分的滚轮高度。并在这些基础上加入一些防抖机制,让虚拟滚动更加流畅。changeTableData(){//在tbody区域的scroll事件中调用virtualScrollMap[key]=()=>{//1.计算当前需要显示的数据,保证tr的最大值不超过20//2.填充margin虚拟部分的滚动高度//3.增加防抖};}//tbody区域的滚动事件onScroll=()=>{//调用由提供的钩子changeTableDatavirtualScrollMap[key]();}上面的例子只是用来展示逻辑,完整实现了changeTableData功能,可以点击github地址查看。效果显示,在tbody区实现数据驱动、差异化更新、虚拟滚动后,2021年最后一天,10000个未打卡商品将按设定步骤释放。效果如下:newGridManager(table,{//启用虚拟滚动@2.18.0virtualScroll:{//使用supportTreeData和fullColumn时虚拟滚动无效。//要使用静态导出,必须配置一个处理程序,否则导出数据的长度为virtualNum;//打印时只对当前配置virtualNum的item个数有效useVirtualScroll:true,//实际渲染的Tr个数,当这个值大于当前页面的数据长度时,虚拟滚动不会生效virtualNum:10},//...其他配置项});从gif可以看出,虽然有10000条数据,但是tbody区域的tr节点数量依然保持在10个。表格上的margin根据滚动轴的位置不断变化,支撑着表格的高度区域。开源并不容易。最近听杨某说要建一个组件库。聊天中,我想起了六年前GridManager的模样。开源不易,希望我们能坚持下去。