虚拟卷帘,大列表滚动 react-virtual-list,支持动态高度
借助罗永浩的口头禅:”少废话,先看东西“。
virtual-list
在使用微博的时候,当H5网页版微博数超过了一定数量,比如有 1000 条微博时,这时候刷微博不管是点击弹出或者滚动都会特别的卡,很多时候会导致微博APP闪退。
当然这不是微博服务器或者手机的问题,而是前端开发里面比较常见的长列表渲染问题。实际上并没有必要一次性把 1000 条微博都渲染出来,只需要渲染可视区域内的元素就行,这样明显数量要少得多。
之前在做微博电影的时候研究写过Vue版本的virtual-list,现在研究下React版本的如何实现!
鉴于React那简陋的API,没有Vue的computed和watch[最核心],实现起来有点麻烦【代码啰嗦】!
Vue 社区通常使用开源项目 vue-virtual-scroll-list 和 vue-virtual-scroller 来优化这种无限列表的场景。
React 社区这边比较知名的就是 react-virtualized 和 react-window ,于是撸一个简单够用的版本virtual-list。
下面简单说下简陋版 react-virtual-list 的实现,首先看下这个组件接受的属性:
1 | export interface RowRendererParams { |
height 是可视区域的高度,rowHeight 是每一行的高度,total 是总的有多少行,rowRenderer 是每一行要怎样渲染。看下 render 方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23render() {
const { height, total, rowHeight } = this.props;
return (
<div
style={{
overflowX: "hidden",
overflowY: "auto",
height
}}
onScroll={this.onScroll}
ref={container => (this.scrollingContainer = container)}
>
<div
style={{
height: total * rowHeight,
position: "relative"
}}
>
{this.renderDisplayContent()}
</div>
</div>
);
}
最外层的 div 为可视区域,并且设置超过的时候显示滚动条。里面的 div 设置完整的高度,也就是每一行的高度乘以总的行数。然后监听最外层的滚动事件:1
2
3
4
5
6
7
8
9onScroll = (e: React.UIEvent<any>) => {
if (e.target === this.scrollingContainer) {
const { scrollTop } = e.target as any;
this.setState({
scrollTop
});
}
};
每次滚动的时候,更新一下 scrollTop,触发 render。这里可以对 onScroll 做下节流:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30get limit() {
const { rowHeight, height } = this.props;
return Math.ceil(height / rowHeight);
}
renderDisplayContent = () => {
const { scrollTop } = this.state;
const { rowHeight, rowRenderer, total } = this.props;
const startIndex = Math.floor(scrollTop / rowHeight);
const endIndex = Math.min(startIndex + this.limit, total - 1);
let content = [];
for (let i = startIndex; i <= endIndex; i++) {
content.push(
rowRenderer({
index: i,
style: {
height: rowHeight,
left: 0,
right: 0,
position: "absolute",
top: i * rowHeight
}
})
);
}
return content;
};
最后是最核心的方法,renderDisplayContent,决定着可视区域里面显示哪些子元素。通过 scrollTop 我们可以知道应该从第几个子元素开始渲染, 然后通过 height 和 rowHeight 算出可视化区域可以显示的子元素个数,最终就可以知道结束的索引。然后调用 rowRenderer 方法,获得完整的显示列表。
完整代码
1 | import * as React from 'react'; |
1 | import React from 'react'; |