用react实现虚拟滚动组件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用react实现虚拟滚动组件相关的知识,希望对你有一定的参考价值。
参考技术A 存在一个数据量大的列表,如select、list,可能存在1000个数据项传统做法是直接将1000个item渲染到页面上,即渲染1000个dom
从上图可以看出,可视区域范围内,仅有7个item,也就是说,不可见的993个元素的存在是浪费资源,从而导致渲染时占满内存、造成页面卡顿。
从这里我们可以入手优化这个list。
既然可视区域只有至多7个元素可见,那么就仅仅渲染这7个dom,不渲染剩下的993个dom。
我们需要计算出如下的数据:
我们可以用到 offsetHeight 属性,元素的可视高度
在此之前需要先定义一个滚动容器,并使用ref将其管理起来,并且设置容器高度 height ,和 overflow-y , 让它滚动起来。 这里为了组件的通用性,我们将 height 和 width 都通过父组件传入的方式获取。
这里我们需要先将第一个子元素渲染出来才能动态地获取它的高度, 同样,我们将列表通过props传入
用可视化区域的高度 除以 单个元素的高度,再向上取整,因为存在一些可见,但是不完全可见的元素,所以这里向上取整。
滚动容器中有个属性叫 scrollTop ,表示当前已滚动的高度,也就是上方不可见的区域。
我们用 scrollTop 除以单个元素的高度 domHeight ,再向下取整,即可得到当前可见区域第一个元素的下标。
至此我们可以将上边需要动态计算的几个变量存入state
下面开始渲染。
这里需要截取 listDom , 使用 slice() 方法。截取起始位置为 currentIndex ,结束为止为 currentIndex + domCount
在这里我们会发现,列表上只有7个元素,且无法滚动
我们还没有给元素绑定滚动事件。
这里我们将上述计算逻辑提到一个函数中进行,并将其绑定scroll
绑定事件后发现还是无法滚动...
原来我们还需要给列表设置上下空白区域,撑开列表,不然无法模拟出来真是列表的高度。
我们继续计算上下空白的高度。
上空白的高度,我们已经计算出了当前可视区域第一个元素的下标了,也计算出了单个元素的站位高度那么
下空白的高度
整个列表的高度 - 可视区域的元素高度 - 上空白的高度
将这两个变量也存入state
然后再将上下两个空白元素添加到dom结构中占位,此时需要将计算 domHeight 的取值下标改为[1]
这里可以看到dom结构中只有几个可见的dom, 并且滑动时动态变化。
渲染效率也大大提高。
可以明显感觉到变快了
在这里我们渲染的时候事在对 listDom 在不断地增删、也就是在不断的增加、删除dom。
那么可不可以不增加删除、或者尽量少地增加删除dom实现我们的功能呢?
element_diff (相同层级的虚拟dom发生变化)
如滚动前 A B C D
滚动后 B C D E
如果不加key,则无法判断 B C D是否还是原来的B C D
对比时 发现A!=B,则会删除A,添加B,以此类推 删除B C D、插入 C D E
添加key后,发现B C D没有变化 ,仅仅需要删除A 插入E即可
Js div在React组件中滚动到底部
通过编写函数scrollToBot我遇到了问题。该函数将由componentDidMount和componentDidUpdate调用。但div不会滚动。我不知道这个功能有什么问题。我必须使用JQuery来实现这个功能吗?
提前致谢。
scrollToBot(){
console.log(this.textAreaDiv.offsetHeight); // 4000
if(this.textAreaDiv.offsetHeight>3000){
console.log("should scoll!!!!!!!!!!!!!!"); // showed
this.textAreaDiv.scrollTop=2000;
}
console.log('run scrollTo'); // showed
}
componentDidMount(){
this.scrollToBot();
}
componentDidUpdate(){
this.scrollToBot();
}
答案
这在React中不起作用,因为它使用Virtual DOM来访问需要使用Refs的真正DOM元素,如React Documents中所述
另一答案
在你的JSX中使用ref
来从你的反应组件的其余部分访问dom元素。
例:
...
textAreaDiv: null
setInputRef(dom){
this.textAreaDiv = dom
}
render(){
<div ref={this.setInputRef}/>
}
`
以上是关于用react实现虚拟滚动组件的主要内容,如果未能解决你的问题,请参考以下文章
放弃antd table,基于React手写一个虚拟滚动的表格