首页 > 解决方案 > 在反应中动态重新定位弹出框时防止闪烁

问题描述

我正在尝试像react-laag文档中显示的示例那样动态地重新定位弹出框。

以下是该示例中发生的情况:滚动时,如果弹出框即将消失,它会移动,以便只要切换弹出框的按钮可见,它就会停留在视口内。

我想使用IntersectionObserverAPI来完成同样的事情,到目前为止,这就是我所做的,

import React, { useState, useEffect, useRef, useLayoutEffect } from "react";

function CustomPopOver(props) {
  const menu = useRef(null);
  const scrollRef = useRef(null);
  const btn = useRef(null);
  const [show, setShow] = useState(false);

  useEffect(() => {
    scrollRef.current.scrollLeft = 300;
    scrollRef.current.scrollTop = 300;
  }, []);

  useLayoutEffect(() => {
    if (menu.current) {
      createObserver();
    }
  });

  function createObserver() {
    let options = {
      root: null,
      rootMargin: "0px",
      threshold: [0.99,0]
    };
    let observer = new IntersectionObserver(handleIntersect, options);
    observer.observe(menu.current);
  }

  function handleIntersect(entries, observer) {
    entries.forEach((entry) => {
      if (entry.intersectionRatio < 1) {
        if (menu.current) {
          const { height: iht, y: iy } = entry.intersectionRect;
          const { height: bht, y: by } = entry.boundingClientRect;
          if (iht < bht) {
            menu.current.style.top =
              640 -
              (bht + btn.current.getBoundingClientRect().height) -
              20 +
              "px";
          }
          if (iy > by) {
            menu.current.style.top = 640 + "px";
          }
          // console.log(entry.intersectionRect, entry.boundingClientRect);
        }
      }
    });
  }

  return (
    <div
      ref={scrollRef}
      style={{
        position: "relative",
        height: "600px",
        width: "600px",
        overflow: "scroll",
        backgroundColor: "#f9fafb"
      }}
    >
      <button
        ref={btn}
        className="btn btn-primary"
        style={{
          position: "relative",
          width: "120px",
          top: "600px",
          left: "650px"
        }}
        onClick={() => {
          setShow(!show);
        }}
      >
        {!show ? "Show" : "Hide"}
      </button>
      {show ? (
        <ul
          ref={menu}
          className="menu"
          style={{
            position: "absolute",
            left: "670px",
            top: "650px"
          }}
        >
          <li className="popup-list">item 1</li>
          <li className="popup-list">item 2</li>
          <li className="popup-list">item 3</li>
          <li className="popup-list">item 4</li>
        </ul>
      ) : null}
      <div style={{ width: "1500px", height: "1500px" }}></div>
    </div>
  );
}

export default CustomPopOver;

我只介绍了顶部和底部边界的情况。当我在弹出框切换为可见向上或向下滚动时,它按预期工作。当弹出框到达顶部或底部边界时,它会向上或向下移动。这是我的问题,当在切换弹出框之前向下滚动按钮以使弹出框无法完全显示时,弹出框在从该位置切换时确实会向上移动,但这会产生令人不快的闪烁效果。这可能是因为 intersectionObserver 仅在弹出框位于 DOM 之后才观察到它,因此当弹出框正确定位时闪烁的原因。

我认为这可能是因为我使用了来自useEffect()的观察者,所以我尝试使用useLayoutEffect()进行相同的操作,但结果没有变化。我为上面的代码创建了一个CodeSandBox。我非常感谢有关如何从这里迁移的任何意见。提前致谢!

标签: javascriptreactjsreact-hooksuse-effectintersection-observer

解决方案


推荐阅读