如果 DOM 发生变化,我找不到重新加载事件监听器的好方法

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

我创建了一个 MouseContext,目标是在鼠标悬停时播放自定义动画。

如果可能的话,我希望只使用 useRef 来做到这一点,但我发现在我的应用程序的整个生命周期中必须对任何需要悬停操作的元素添加引用是一种耻辱。

所以我尝试使用这样的手动事件侦听器:

  useEffect(() => {
      function inOutHandler(event) {
        event.preventDefault();
        const cursorType = event.type === "mouseenter" ? "active" : "";
        if (
          window.getComputedStyle(event.target)["cursor"].split(", ")[1] ===
          "pointer"
        )
          mouseHandler({ type: "mouseHover", cursorType: cursorType });

        window.removeEventListener("mouseenter", inOutHandler);
        window.removeEventListener("mouseout", inOutHandler);
      }

      const links = document.querySelectorAll(
        "a, .button, button"
      );
      for (let link of links) {
        link.addEventListener("mouseenter", inOutHandler);
        link.addEventListener("mouseout", inOutHandler);
      }
  }, []);

好吧,听起来不错,但是当一个新元素添加到 DOM 中时,我必须再次听他的,处理起来很混乱。

我再次尝试了一些东西,使用 MutationObserver :

  const mutationObserver = new MutationObserver(async (mutationList, obs) => {
    if (mutationList[0].addedNodes) {
      function inOutHandler(event) {
        event.preventDefault();
        const cursorType = event.type === "mouseenter" ? "active" : "";
        if (
          window.getComputedStyle(event.target)["cursor"].split(", ")[1] ===
          "pointer"
        )
          mouseHandler({ type: "mouseHover", cursorType: cursorType });

        window.removeEventListener("mouseenter", inOutHandler);
        window.removeEventListener("mouseout", inOutHandler);
      }

      const links = document.querySelectorAll(
        "a, .admin .button, button"
      );
      for (let link of links) {
        link.addEventListener("mouseenter", inOutHandler);
        link.addEventListener("mouseout", inOutHandler);
      }
    }
  });

  useEffect(() => {
    if (mainRef.current) {
      mutationObserver.observe(mainRef.current, {
        childList: true,
        subtree: true,
      });

      return () => {
        mutationObserver.disconnect();
      };
    }
  }, [mutationObserver]);

这就是工作!但 : 突变观察者也在监听从 dom 中消失的元素,因此,每次幻灯片更改(例如),我的监听器都会执行两次。这在性能方面给我带来了问题。

你们有什么建议可以帮助我实现这一目标吗?

reactjs express mutation-observers
1个回答
0
投票

感谢 jfriend00 :

听起来您可能想在您收听的地方使用事件传播 用于公共父级而不是实际 DOM 元素上的事件。 这样,您可以在父级上安装一次侦听器并自动 查看所有子事件,即使 DOM 元素来来去去(只要 您正在收听的家长不会改变)。

我不知道父侦听器会处理 DOM 更改。 因为我检查当前元素 event.target 是否设置为指针,所以仅适用于链接和按钮,谢谢!

就性能而言,这需要测试应用程序的所有元素,我不知道这是否非常有影响。

新代码:

  function inOutHandler(event) {
    const cursorType = event.type === "mouseenter" ? "active" : "";
    if (
      window.getComputedStyle(event.target)["cursor"].split(", ")[1] ===
      "pointer"
    )
      mouseHandler({ type: "mouseHover", cursorType: cursorType });

    mainRef.current.removeEventListener("mouseenter", inOutHandler);
    mainRef.current.removeEventListener("mouseout", inOutHandler);
  }

  useEffect(() => {
    if (!loader) {
      mainRef.current.addEventListener("mouseenter", inOutHandler, true); // don't forget the true
      mainRef.current.addEventListener("mouseout", inOutHandler, true);
    }
  }, [loader]);
© www.soinside.com 2019 - 2024. All rights reserved.