在react中滚动到视图中

IT技术 javascript reactjs scroll
2021-04-03 07:17:33

我正在制作一个简单的react应用程序,其中有两个不同的div's..

一种带有选择输入和选择列表的,

  <div id="container">
    <div className="_2iA8p44d0WZ">
      <span className="chip _7ahQImy">Item One</span>
      <span className="chip _7ahQImy">Item Two</span>
      <span className="chip _7ahQImy">Item Three</span>
      <span className="chip _7ahQImy">Item Four</span>
      <span className="chip _7ahQImy">Item Five</span>
      <input
        type="text"
        className="searchBox"
        id="search_input"
        placeholder="Select"
        autoComplete="off"
        value=""
      />
    </div>
  </div>

另一个将列出所选选项为fieldset

  <div>
    {selectedElements.map((item, i) => (
      <div key={i} className="selected-element" ref={scrollDiv}>
        <fieldset>
          <legend>{item}</legend>
        </fieldset>
      </div>
    ))}
  </div>

基于此解决方案,我已添加createRef到所选元素中,例如,

<div key={i} className="selected-element" ref={scrollDiv}>
</div>

然后我使用 Javascript 查询方法来获取 DOM 元素,例如,

  const chipsArray = document.querySelectorAll("#container > div > .chip");

向所有元素添加了单击事件侦听器,例如,

  chipsArray.forEach((elem, index) => {
    elem.addEventListener("click", scrollSmoothHandler);
  });

然后scrollSmoothHandler喜欢,

const scrollDiv = createRef();

  const scrollSmoothHandler = () => {
    console.log(scrollDiv.current);
    if (scrollDiv.current) {
      scrollDiv.current.scrollIntoView({ behavior: "smooth" });
    }
  };

但这并不像预期的那样工作。

要求:

单击 中的任何项目first div,然后其相关字段集需要进入smooth scrolled另一个 div..

例如: 如果用户单击该元素的Item Four<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>

然后需要滚动到相关的字段集。这里带有图例的字段集为Item Four..

我认为也在react上制作 js dom 查询方法,这似乎不是react的实现方式。任何人都可以请帮助我实现在单击所选项目时滚动到相关字段集的结果..

编辑 React 功能组件(分叉)

1个回答

问题

  1. React.createRef实际上只在基于类的组件中有效。如果在功能组件主体中使用,则 ref 将在每个渲染周期重新创建。
  2. 不要使用 DOM 查询选择器将onClick侦听器附加到 DOM 元素。这些生活在外面的react,你需要记住清理它们(即删除它们),这样你就不会出现内存泄漏。使用 React 的onClickprop。
  3. selectedElements被映射你附上相同裁判每一个元素,所以最后一组是一个你的UI获得。

解决方案

  1. 使用React.useRef在功能部件主体存储阵列的react参附加到要滚动到视图的每个元素。
  2. scrollSmoothHandler直接附加到 eachspanonClickprops上。
  3. 将 1. 中创建的 ref 数组中的每个 ref 附加到您要滚动到的每个映射字段集。

代码

import React, { createRef, useRef } from "react";
import { render } from "react-dom";

const App = () => {
  const selectedElements = [
    "Item One",
    "Item Two",
    "Item Three",
    "Item Four",
    "Item Five"
  ];

  // React ref to store array of refs
  const scrollRefs = useRef([]);

  // Populate scrollable refs, only create them once
  // if the selectedElements array length is expected to change there is a workaround
  scrollRefs.current = [...Array(selectedElements.length).keys()].map(
    (_, i) => scrollRefs.current[i] ?? createRef()
  );

  // Curried handler to take index and return click handler
  const scrollSmoothHandler = (index) => () => {
    scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
  };

  return (
    <div>
      <div id="container">
        <div className="_2iA8p44d0WZ">
          {selectedElements.map((el, i) => (
            <span
              className="chip _7ahQImy"
              onClick={scrollSmoothHandler(i)} // <-- pass index to curried handler
            >
              {el}
            </span>
          ))}
          <input
            type="text"
            className="searchBox"
            id="search_input"
            placeholder="Select"
            autoComplete="off"
            value=""
          />
        </div>
      </div>
      <div>
        {selectedElements.map((item, i) => (
          <div
            key={i}
            className="selected-element"
            ref={scrollRefs.current[i]} // <-- pass scroll ref @ index i
          >
            <fieldset>
              <legend>{item}</legend>
            </fieldset>
          </div>
        ))}
      </div>
    </div>
  );
};

解决方案#2

由于您无法更新divwith 中的任何元素id="container"并且所有onClick处理程序都需要通过查询 DOM 来附加,因此您仍然可以使用柯里化scrollSmoothHandler回调并在范围内包含索引。您需要一个useEffect钩子在初始渲染查询 DOM 以便安装跨度,并需要一个useState钩子来存储“加载”状态。该状态对于触发重新渲染并scrollRefsscrollSmoothHandler回调中重新封装是必要

const App = () => {
  const selectedElements = [
    "Item One",
    "Item Two",
    "Item Three",
    "Item Four",
    "Item Five"
  ];

  const [loaded, setLoaded] = useState(false);
  const scrollRefs = useRef([]);

  const scrollSmoothHandler = (index) => () => {
    scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
  };

  useEffect(() => {
    const chipsArray = document.querySelectorAll("#container > div > .chip");

    if (!loaded) {
      scrollRefs.current = [...Array(chipsArray.length).keys()].map(
        (_, i) => scrollRefs.current[i] ?? createRef()
      );

      chipsArray.forEach((elem, index) => {
        elem.addEventListener("click", scrollSmoothHandler(index));
      });
      setLoaded(true);
    }
  }, [loaded]);

  return (
    <div>
      <div id="container">
        <div className="_2iA8p44d0WZ">
          <span className="chip _7ahQImy">Item One</span>
          <span className="chip _7ahQImy">Item Two</span>
          <span className="chip _7ahQImy">Item Three</span>
          <span className="chip _7ahQImy">Item Four</span>
          <span className="chip _7ahQImy">Item Five</span>
          <input
            type="text"
            className="searchBox"
            id="search_input"
            placeholder="Select"
            autoComplete="off"
            value=""
          />
        </div>
      </div>
      <div>
        {selectedElements.map((item, i) => (
          <div key={i} className="selected-element" ref={scrollRefs.current[i]}>
            <fieldset>
              <legend>{item}</legend>
            </fieldset>
          </div>
        ))}
      </div>
    </div>
  );
};

编辑滚动到视图中的react

非常感谢 Reese,您能否在问题下查看上述评论onClick={scrollSmoothHandler(i)}
2021-05-25 07:17:33
谢谢 Reese,最后的要求是,如果我单击该库中任何选定的芯片(关闭图标除外),则需要滚动选定项目的字段集。那个库的代码,我不能单独修改第一个 div 代码..所以只有我还在我的问题代码和框中使用 DOM 制作了点击事件处理程序..我很抱歉没有提到..当然请完成这个场景并让我知道更新的解决方案请..
2021-05-29 07:17:33
@Undefined 啊,我明白了。让我看看我能想出什么。只是我理解正确,您不能修改id="container"div 中的跨度并附加scrollSmoothHandler, ref 创建需要根据从 DOM 查询的内容是动态的?
2021-06-03 07:17:33
而且我只需要第一个 div/span 标签的帮助,其中单击事件发生,因为在包含字段集的第二部分中,您可以修改任何内容并且没有问题。
2021-06-05 07:17:33
所以一般来说,我需要在加载 DOM 之后添加 click 事件,但无论如何我都需要动态地制作它,因为这些不是真实应用程序中的硬编码 jsx..
2021-06-22 07:17:33