React:检查不同组件中的元素是否重叠

use*_*307 4 ref overlap reactjs

我正在查看许多检查元素是否重叠的答案,但它们不适用。

我有一个包装组件,它有一个位置固定的标头和子组件

const Wrapper = ({ children }) => {

  return (
    <>
    <Header/>
    {children}
    </>
  )
};

export default Wrapper
Run Code Online (Sandbox Code Playgroud)

我需要知道标题何时与几个不同页面(子页面)中的某些部分重叠,以便更改标题颜色

我试图在包装器组件中进行检测,但元素不存在或容器无法访问

我是否需要将引用从包装器一直传递给所有孩子?有没有更简单的方法来做到这一点?

谢谢

Joe*_*oey 6

我能想到几种方法,一种是你提到的方法,传递参考文献并进行一系列计算,还有下面的一些方法。

页面的硬编码高度

这基本上可以通过在头文件中包含一个大的 switch case 并检查滚动目标的偏移滚动位置来实现。

getBackgroundColor = (scrollPosition) => {
    switch (true) {
        case scrollPosition <= $('#page1').height:
            return 'red'
        case scrollPosition <= $('#page1').height + $('#page2').height:
            return 'blue'
        case scrollPosition <= $('#page1').height + $('#page2').height + $('page3').height
            return 'green'
        default:
            return 'yellow'
    }
}
Run Code Online (Sandbox Code Playgroud)

这有明显的缺陷,一是,如果页面内容是动态的或者经常变化,它可能不起作用,每次重新渲染时检查高度可能会导致回流问题,而这需要了解页面上的页面ID。(注意:这个片段只是为了证明概念,它需要几周的时间)。

路口观察者(推荐方式)

Intersection Observer是一个很棒的 AP​​I,它允许您以高性能的方式观察元素,并通过恒定测量减少替代方式的布​​局抖动,这是我用 React 和 Intersection Observer 制作的一个示例,https: //codesandbox.io/s/relaxed-斯宾塞-yrozp。如果您有数百个目标,这可能不是最好的,但我还没有对此进行任何基准测试,所以不确定。它也被认为是“实验性的”,但具有良好的浏览器支持(不是 IE)。

以下是下面的大部分代码和框,只是为了获得一个想法。

React.useEffect(() => {
    let headerRect = document.getElementById("header").getBoundingClientRect();
    let el = document.getElementById("wrapper");
    let targets = [...document.getElementsByClassName("block")];

    let callback = (entries, observer) => {
      entries.forEach(entry => {
        let doesOverlap = entry.boundingClientRect.y <= headerRect.bottom;
        if (doesOverlap) {
          let background = entry.target.style.background;
          setColor(background);
        }
      });
    };

    let io = new IntersectionObserver(callback, {
      root: el,
      threshold: [0, 0.1, 0.95, 1]
    });
    targets.forEach(target => io.observe(target));

    return () => {
      targets.forEach(target => io.unobserve(target));
    };
  }, []);
Run Code Online (Sandbox Code Playgroud)

另请注意,这不是最“React”的做事方式,因为它很大程度上依赖于ids,但是您可以通过在我使用过 dom 选择的所有地方传递 ref 来解决这个问题,但这可能会变得笨拙。