React:检查不同组件中的元素是否重叠
React: check if elements in different components overlap
我正在查看许多检查元素是否重叠的答案,但它们不适用。
我有一个包装器组件,它有一个固定位置的 header 和 children
const Wrapper = ({ children }) => {
return (
<>
<Header/>
{children}
</>
)
};
export default Wrapper
我需要知道 header 何时与几个不同页面 (children) 中的某些部分重叠,以便更改 header 颜色
我试图在包装器组件中进行检测,但元素不存在或容器无法访问
我是否需要将引用从包装器一直传递到所有 children?有更简单的方法吗?
谢谢
我能想到几种方法,一种是你提到的那种,传递引用并进行大量计算,下面还有一些其他方法。
页面的硬编码高度
这基本上可以通过在你的头文件中有一个大的开关盒并检查你的滚动目标的偏移滚动位置来工作。
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'
}
}
这有明显的缺陷,一个是,如果页面内容是动态的或经常变化,它可能不起作用,每次重新渲染检查高度可能会导致回流问题,这需要了解页面上的页面 ID。 (注意:此片段只是为了证明概念,需要 tweeks)。
路口观察器(推荐方式)
Intersection observer 是一个很棒的 API,它允许您以高效的方式观察元素,并通过不断测量的替代方式减少布局抖动
这是我用 React 和 Intersection Observer 制作的示例,https://codesandbox.io/s/relaxed-spence-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));
};
}, []);
另外请注意,这不是最“反应”的做事方式,因为它在很大程度上依赖于 ids
,但您可以通过在我使用 dom 选择的任何地方传递引用来解决这个问题,但这可能会变得笨重。
我正在查看许多检查元素是否重叠的答案,但它们不适用。
我有一个包装器组件,它有一个固定位置的 header 和 children
const Wrapper = ({ children }) => {
return (
<>
<Header/>
{children}
</>
)
};
export default Wrapper
我需要知道 header 何时与几个不同页面 (children) 中的某些部分重叠,以便更改 header 颜色
我试图在包装器组件中进行检测,但元素不存在或容器无法访问
我是否需要将引用从包装器一直传递到所有 children?有更简单的方法吗?
谢谢
我能想到几种方法,一种是你提到的那种,传递引用并进行大量计算,下面还有一些其他方法。
页面的硬编码高度
这基本上可以通过在你的头文件中有一个大的开关盒并检查你的滚动目标的偏移滚动位置来工作。
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'
}
}
这有明显的缺陷,一个是,如果页面内容是动态的或经常变化,它可能不起作用,每次重新渲染检查高度可能会导致回流问题,这需要了解页面上的页面 ID。 (注意:此片段只是为了证明概念,需要 tweeks)。
路口观察器(推荐方式)
Intersection observer 是一个很棒的 API,它允许您以高效的方式观察元素,并通过不断测量的替代方式减少布局抖动 这是我用 React 和 Intersection Observer 制作的示例,https://codesandbox.io/s/relaxed-spence-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));
};
}, []);
另外请注意,这不是最“反应”的做事方式,因为它在很大程度上依赖于 ids
,但您可以通过在我使用 dom 选择的任何地方传递引用来解决这个问题,但这可能会变得笨重。