有什么方法可以检查 div 是否位于另一个 div 的底部(充当父级或容器)。
所以基本上我制作了演示,其中 div 中有可以添加和删除的子元素(
items, setItems
),并且您还可以通过单击 div 来更改它们的高度(这里很重要)。还有另一个 div,它不处于 items
状态,我想更改该项目的标题,如果它位于其父 div 的底部(也 items
与该 div 具有相同的父级)有)。
我尝试过查看父容器的
getBoundingClientRect()
和这个“蓝色”div,让我们这样称呼它,它会正常工作,仅当 items
具有相同的高度时,但是一旦删除一个项目并通过单击 div 更改其高度,它将不起作用。它将显示它位于屏幕底部(标题为真),但实际上并非如此。我的代码
App.js - 仅用于演示目的
import "./styles.css";
import { useState, useEffect, useRef } from "react";
export default function App() {
const arrayItems = [
{
id: 1,
name: "test",
resized: false
},
{
id: 2,
name: "test1",
resized: false
},
{
id: 3,
name: "test2",
resized: false
}
];
const [items, setItems] = useState(arrayItems);
const [title, setTitle] = useState(false);
const parentRef = useRef(null);
const itemsRef = useRef(null);
useEffect(() => {
if (
parentRef?.current.getBoundingClientRect().bottom -
itemsRef?.current.getBoundingClientRect().height <=
itemsRef?.current.getBoundingClientRect().top
) {
setTitle(true);
} else {
setTitle(false);
}
}, [parentRef, items]);
const handleClick = () => {
const maxValue = Math.max(...items.map((item) => item.id)) + 1;
setItems((prev) => [
...prev,
{ id: maxValue, name: "testValue", resized: false }
]);
};
const handleDelete = () => {
setItems((prev) => prev.slice(0, prev.length - 1));
};
const handleResize = (item) => {
setItems((prev) =>
prev.map((itemOld) => {
if (itemOld.id === item.id) {
return itemOld.resized === true
? { ...itemOld, resized: false }
: { ...itemOld, resized: true };
} else {
return itemOld;
}
})
);
};
console.log(items);
return (
<div className="App">
<button onClick={handleClick}>Add new</button>
<button onClick={handleDelete}>Delete last</button>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div ref={parentRef} className="container">
{items?.map((item) => {
return (
<div
onClick={() => handleResize(item)}
style={{ height: item.resized ? "70px" : "20px" }}
key={item.id}
className="container-item"
>
<p>{item.name}</p>
</div>
);
})}
<div ref={itemsRef} id="title-div">
{title ? "At the bottom" : "Not at the bottom"}
</div>
</div>
</div>
);
}
样式.css
.App {
font-family: sans-serif;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 1rem;
}
* {
margin: 0;
padding: 0;
}
.container {
width: 600px;
height: 300px;
background-color: gray;
display: flex;
flex-direction: column;
}
.container-item {
width: 100%;
background-color: hotpink;
}
#title-div {
width: 100%;
padding: 1rem;
background-color: blue;
color: white;
}
我想做的事
代码
useEffect(() => {
if (
parentRef?.current.clientHeight <=
itemsRef?.current.getBoundingClientRect().top -
parentRef?.current.getBoundingClientRect().top +
itemsRef?.current.clientHeight
) {
setTitle(true);
} else {
setTitle(false);
}
}, [parentRef, items, itemsRef]);
import { useEffect, useState, useRef } from "react";
const useBottomRectReached = () => {
const [isBottomRectReached, setIsBottomRectReached] = useState(false);
const ref = useRef<HTMLElement | null>(null);
useEffect(() => {
const handleScroll = () => {
if (ref.current) {
const rect = ref.current.getBoundingClientRect();
const windowHeight = window.innerHeight;
const isReached = rect.top >= windowHeight * 0.6;
setIsBottomRectReached(isReached);
}
};
window.addEventListener("scroll", handleScroll);
handleScroll();
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return [ref, isBottomRectReached] as const;
};
export default useBottomRectReached;
现在您可以通过可配置的阈值在应用程序中导入和使用(在此上下文中默认值为 0.6)
const [ref, isBottomRectReached] = useBottomRectReached({
threshold: 0.8
});