Reactjs中从零开始的无限滚动,并带有交叉观察器

问题描述 投票:1回答:1

背景:我使用交叉观察器构建了一个无限滚动器,目的是重新使用dom节点(也称为窗口)。当div滚动离开视口的顶部时,它绝对位于div序列的末尾,反之亦然,退出底部的div则相反。

问题:如果您向上滚动太快,则将完全滚动到div上方。同时,如果您向下滚动得太快,则不会发生这种情况。无法找出原因。

Codesandbox(打开demo in fullscreen https://codesandbox.io/s/cranky-pasteur-wckzm

代码:

/* eslint no-unused-vars: 0 */
/* eslint react-hooks/exhaustive-deps: 0 */
/* eslint no-sequences: 0 */

import React, { useEffect } from "react";
import "./styles.css";

const App = () => {
  useEffect(() => {
    const divs = document.querySelectorAll('.abc')

    const options = {
      root: null,
      threshold: 0,
      rootMargin: '0px'
    }

    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting === false) {
          if (entry.boundingClientRect.top < 0 && window.pageYOffset > 320) {
            console.log('element scrolled off top')
            const lastDiv = entry.target.parentNode.lastElementChild
            const firstDiv = entry.target.parentNode.firstElementChild

            const lastDivTopAmount = Number(lastDiv.style.top.split('').slice(0, -2).join(''))

            firstDiv.style.top = `${lastDivTopAmount+320}px`
            firstDiv.parentNode.appendChild(firstDiv)
            return
          }

          if (entry.boundingClientRect.bottom > 1250 && window.pageYOffset > 320) {
            console.log('element scrolled off bottom')
            const firstDiv = entry.target.parentNode.firstElementChild
            const lastDiv = entry.target.parentNode.lastElementChild

            const firstDivTopAmount = Number(firstDiv.style.top.split('').slice(0, -2).join(''))

            lastDiv.style.top = `${firstDivTopAmount-320}px`
            lastDiv.parentNode.prepend(lastDiv)
            return
          }
        }
      })
    }, options)

    divs.forEach(div => {
      observer.observe(div)
    })
}, [])

  return (
    <div>
      <div className="visibleRows">
        <div 
          style={{top: '0px', backgroundColor: 'blue', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-1 abc"
        />
        <div
          style={{top: '320px', backgroundColor: 'red', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-2 abc"
        />
        <div
          style={{top: '640px', backgroundColor: 'green', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-3 abc"
        />
        <div
          style={{top: '960px', backgroundColor: 'purple', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-4 abc"
        />
        <div
          style={{top: '1280px', backgroundColor: 'yellow', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-5 abc"
        />
        <div 
          style={{top: '1600px', backgroundColor: 'pink', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-6 abc"
        />
        <div 
          style={{top: '1920px', backgroundColor: 'orange', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-7 abc"
        />
        <div 
          style={{top:'2240px', backgroundColor: 'cyan', height: '320px', width: '580px', outline: '4px solid pink'}}
          className="baby-div-8 abc"
        />
      </div>
  </div>
  );
};

export default App;

Styles.css

.abc {
  position: absolute;
  height: 320px;
  width: 580px;
  outline: 4px solid pink;
}
javascript reactjs performance scroll infinite-scroll
1个回答
0
投票

仅当观察到的条目越过threshold时才会触发IntersectionObserver回调。由于您在选项中定义的threshold0(并且根为null),因此这意味着仅当您的一个框在threshold上移动时(即当框进入或退出视口)。

令人困惑的部分是entries.forEach(...) 不会遍历所有观察到的目标,它只会获取超过阈值的实体。

所以您的第一个条件if (entry.boundingClientRect.top < 0 && window.pageYOffset > 320) { ... }有效,因为当框从视口顶部滚动时,可以实现这些条件。但是,您的第二个条件if (entry.boundingClientRect.bottom > 1250 && window.pageYOffset > 320) { ... }中的条件将可能永远无法满足,因为对于931bottom > 1250),视口需要为931 + 320 > 1250高。

我不太确定如何使用IntersectionObserver的方法,因为您不能保证在需要时会超过阈值。如果顶部框以负top开头,并且您刚刚跟踪了“视口顶部”阈值,则可以完成工作……但是在快速滚动时可能会出现问题。

对于scroll event listener,这可能是更好的工作...,或者使用Intersection Observer来复制所有div,而不是实际移动它们。”

© www.soinside.com 2019 - 2024. All rights reserved.