React.js - 如何检查 div 是否位于屏幕底部(动态)

问题描述 投票:0回答:2

有什么方法可以检查 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; }
我想做的事

正如标题所示,我想查看 div 是否位于容器/父 div 的底部。就是这样,该父 div 中的其他项目不能干扰该 div,从某种意义上说,添加、调整大小、删除这些项目不会突然改变我想要分析的 div 的位置(看看它是否位于屏幕底部)

javascript css reactjs
2个回答
0
投票
我提出了自己的解决方案,并且它始终有效。我只需从parentsRef 中扣除“top”,并从itemsRef 中扣除“top”,然后添加itemsRef 的clientHeight。这样它将始终位于容器的底部,无论我删除项目、调整它们的大小等都没关系。

代码

useEffect(() => { if ( parentRef?.current.clientHeight <= itemsRef?.current.getBoundingClientRect().top - parentRef?.current.getBoundingClientRect().top + itemsRef?.current.clientHeight ) { setTitle(true); } else { setTitle(false); } }, [parentRef, items, itemsRef]);
    

0
投票
这是我在 React Typescript 中提出的想法。与下面的解决方案类似,但具有用于可重用和可配置阈值的专用挂钩。简单地比较当前的矩形顶部与窗口高度

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 });
    
© www.soinside.com 2019 - 2024. All rights reserved.