简体   繁体   English

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

[英]React.js - How to check if the div is at the bottom of the screen (dynamically)

Is there any way to check if the div is at the bottom of the another div (acting as a parent, or container).有什么方法可以检查 div 是否位于另一个 div 的底部(充当父级或容器)。

What I tried我试过的

So basically I made demo where there are child elements ( items, setItems ) in the div that can be added and deleted and also you can change the height of them by clicking on the divs (important here).所以基本上我做了演示,其中 div 中有可以添加和删除的子元素( items, setItems ),您也可以通过单击 div 更改它们的高度(在这里很重要)。 Also there is another div, which is not in the items state, where I want to change the title of that item, if it is at the bottom of the his parent div (also items have the same parent as this div has).还有另一个 div,它不在items state 中,我想更改该项目的标题,如果它位于他的父 div 的底部( items也具有与此 div 相同的父项)。

Problem with my solution我的解决方案有问题

I have tried something where I am looking at the getBoundingClientRect() of the parent container and this "blue" div, lets call it like that, and it will work fine, ONLY IF the items have the same height, but soon as a delete the one item and change the height of it by clicking on the div, it will not work.我已经尝试了一些方法,我正在查看父容器的getBoundingClientRect()和这个“蓝色” div,让我们这样称呼它,它会正常工作,只有items具有相同的高度,但尽快删除一项并通过单击 div 更改它的高度,它将不起作用。 It will show that it is on the bottom of the screen (the title will be true) but in reality it is not.它将显示它位于屏幕底部(标题为真),但实际上并非如此。

My code我的代码

App.js - only for demo purposes 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>
  );
}

styles.css styles.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;
}

What I want to make我想做的

As the title suggest I want to see if the div is at the bottom of the container/parent div.正如标题所示,我想查看 div 是否位于容器/父 div 的底部。 That is it, and other items in that parent div, cannot interfere with this div, in sense that adding, resizing, deleting those items, will not suddenly change the position of the div that I want to analyse (to see if it is at the bottom of the screen)就是这样,该父 div 中的其他项目不能干扰该 div,从某种意义上说,添加、调整大小、删除这些项目不会突然改变我要分析的 div 的 position(看看它是否在屏幕底部)

I have come up with my own solution and it works always.我想出了我自己的解决方案,它总是有效的。 I just have to deduct the "top" from parentsRef and "top" from the itemsRef, and add to that the clientHeight of the itemsRef.我只需要从 parentsRef 中减去“top”,从 itemsRef 中减去“top”,然后添加 itemsRef 的 clientHeight。 This way it will always be at the bottom of the container, doesnt matter if I delete the items, resize them etc.这样,它将始终位于容器的底部,无论我是否删除项目、调整它们的大小等。

The code编码

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM