Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-tiny-virtual-list源码阅读 #24

Open
RachelRen opened this issue Jan 15, 2019 · 0 comments
Open

react-tiny-virtual-list源码阅读 #24

RachelRen opened this issue Jan 15, 2019 · 0 comments

Comments

@RachelRen
Copy link
Owner

最近在研究react的性能相关的问题,就学习了一下react-virtualized, 也顺便看了一下react-tiny-virtual-list的源码。然后根据自己的理解,大致实现了一个简单版的。

他的大致流程如下:

  1. 只渲染可视区域的信息
  2. 有两个box,外面那个用来表示可视区,里面那个用来表示是所有的列表项
  3. 每当滚动条滚动的时候,去计算显示哪些
    这里有两种实现方式:
    1. 父元素是position: relative; 子元素absolute;来定位显示元素的位置,动态计算每个元素的位置
  4. 知道这个列表有多少条,也知道没一条的高度

确定一些元素的大小

  1. 每一条item的大小
  2. 可视区域的大小: 这样可以计算需要显示多少条
  3. 另一个父元素的大小,即列表的大小,需要计算滚动条滚动的距离,来计算应该从哪里开始展示
const wrapperStyle = {...STYLE_WRAPPER, height: height + "px"};
const innerHeight =  itemSize * itemCount,
    		innerStyle = {...STYLE_INNER, height: innerHeight + "px"};
return (
    <div ref={this.rootNode} style={wrapperStyle}>
    	<div style={innerStyle}>
    		{items}
    	</div>
    </div>
)

这是展示区域的样式,这里已经确定了每一个item的高度和可视区域的高度来实现的。

滚动计算展示的

这里只做了一个简单的例子,用来计算当滚动的时候,该显示的数据。

这里需要注意的是,当endIndex > lastIndex的时候,说明滚动条已经到底了,那么当endIndex 就该等于lastIndex。
而且在滚动的过程中,加了overscanCount,这是为了有所缓存,不至于滚动的时候,页面有所卡顿。

componentDidMount(){
	this.rootNode.current.addEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
	const rootNode = this.rootNode.current,
		{showCount, overscanCount, lastIndex} = this,
		{itemSize} = this.props,
		scrollTop = rootNode.scrollTop,
		startIndex = parseInt(scrollTop/itemSize) + 1;
	let	endIndex = startIndex +  showCount + overscanCount;
	if(startIndex +  showCount > lastIndex){
		endIndex = lastIndex;
	}
	this.setState({
		startIndex: startIndex,
		endIndex: endIndex
	})
}

性能优化点

  1. 在滚动事件中增加了
handleScroll = () => {
	if(!this.ticking){
		requestAnimationFrame(this.caculateStartAndEndIndex);
		this.ticking = true;
	}

}
  1. 把每个节点的位置记录下来,这样就不需要每次都动态计算了
getStyle(index){
    const style = this.styleCache[index],
    	{itemSize} = this.props;
    
    if(style){
    	return style;
    }
    return this.styleCache[index] = {...STYLE_ITEM, top: index*itemSize + "px", left: 0, height: itemSize+"px"}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant