制作无事件监听器的无限滚动表

为什么会落后呢?



如果在用某种过渡动画渲染巨大的表时没有做其他事情,那么应用程序将滞后,用户将受苦。




在大多数情况下,当我们使用事件侦听器创建具有无限滚动的表时,我们不仅需要执行与视口和行高相关的计算,而且还需要在滚动处理程序中编写很多逻辑以防止重绘次数过多,因为每次回调滚动都会调用setState


该代码将是这样的:


 componentDidMount() { window.addEventListener('scroll', this.handleScroll) } handleScroll(e) { // use window offset and boundingRect const { ...someAttributes } = window; const { ...someBoundingRect } = this.component // some logic prevent re-render if ( ... ) return; // do some math const newIndex = ... // and how many rows should be rendered this.setState({index: newIndex }) } 

但是,还有另一种方法可以实现对表的无限滚动,而无需了解关于window或boundingRect值的任何知识。


这是一个IntersectionObserver 。 来自w3c的定义:


本规范描述了一个API,可用于查找DOM元素(“目标”)相对于其中包含的元素的可见性和位置。

使用此方法时,不需要知道线的高度,视口的顶部或任何其他值即可进行数学计算。



其概念是在每个控制点安排带有索引的锚点,并且每次触发锚点时,获取索引值并重新绘制表格。 因此,您不需要使用DOM高度和视口进行任何数学运算。



索引1的锚定触发器


渲染更多行


IntersectionObserver的代码将是这样。



 handleSentinel = (c) => { if(!this.observer) { //  observer this.observer = new IntersectionObserver( entries => { entries.forEach(e => { //   ,    if (e.isIntersecting) { this.setState( { cursor: +e.target.getAttribute('index') } ); } }); }, { root: document.querySelector('App'), rootMargin: '-30px', } } if (!c) return; //    this.observer.observe(c) } render() { const blockNum = 5; return( ... <tbody> {MOCK_DATA.slice(0, (cursor+1) * blockNum).map(d => <Block> { //       // ,   5  d.id % blockNum === 0 ? <span ref={this.handleSentinel} index={d.id / blockNum} /> : null } </Block>)} </tbody> ... ) } 

Source: https://habr.com/ru/post/zh-CN456046/


All Articles