reactjs 通过IntersectionObserver激活的CSS动画在React中无法正常工作

pftdvrlh  于 2023-04-29  发布在  React
关注(0)|答案(1)|浏览(139)

我试图动画网页,并考虑使用网页上的滚动功能来激活所说的动画。我使用JavaScript学习了一个教程,并没有使用其他库来通过以下代码实现这一点

function App() {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add("show");
      } else {
        entry.target.classList.remove("show");
      }
    });
  });

  const hiddenElements = document.querySelectorAll(".hidden");
  hiddenElements.forEach((el) => observer.observe(el));
  return (
    <div>
      <p className="sample">Sample hello Text</p>
      <p>
        <br />
        <br />
        <br />
        <br />
      </p>
      <p className="hidden">Instruction 1</p>
      <p>
        <br />
        <br />
        <br />
        <br />
      </p>
      <p className="hidden">Instruction 2</p>
      <p>
        <br />
        <br />
        <br />
        <br />
      </p>
      <p className="hidden">Instruction 3</p>
      <p>
        <br />
        <br />
        <br />
        <br />
      </p>
      <div>
        <img className="hidden" src="src/assets/react.svg" />
      </div>
    </div>
  );
}

export default App;

注意:这只是测试代码,使用了break标签,所以有内容可以滚动到。
下面是附带的CSS代码:

body {
  background-color: gray;
}
div {
  display: grid;
  place-items: center;
  align-items: center;
  min-height: 100vh;
}
p {
  font-size: 30px;
  font-style: bold;
  color: black;
}

.hidden {
  transition: all 1.5s;
  width: 50px;
  opacity: 0.5;
  filter: blur(5px);

  transform: translateX(-100%);
}
.show {
  opacity: 1;
  filter: blur(0);
  transform: translateX(0);
}

/*
// Same animations but using keyframes and no additional code to execute upon scrolling, this works // perfectly
.hidden {
  transition: all 1.5s;
  transform: translate(-150%);
  animation: thing 1s linear both;
}
@keyframes thing {
  0% {
    transform: translate(-150%);
    opacity: 0.5;
    filter: blur(5px);
  }
  100% {
    transform: translate(0);
    opacity: 1;
    filter: blur(0);
  }
} */

现在在教程中,他们使用HTML和CSS文件完成了这一点,但在这里我使用React与Vite和Typescript完成了这一点。现在发生的是这样的:

.hidden.show的动画不执行,并且停留在.hidden状态,除非我保存保存保存应用程序功能的.tsx文件而不编辑任何内容。刷新页面后,同样的问题将再次发生,我需要重新保存文件,使其正常工作。
这就是动画执行后的样子:

我还认为,由于文本Instruction1Instruction2是在刷新时,动画将执行,因为他们开始在交叉点,但它仍然遭受同样的问题。
我在一个普通的HTML和JS文件中复制了相同的代码,代码工作正常。我重新做了确切的动画与关键帧没有intersectionObserver代码,它的工作,但这意味着动画只是执行在开始的页面加载,而不是在它正在查看。
我编辑了CSS文件,目标是.hidden的转换,看看是否是CSS文件导致了错误,但在保存任何更改时,网页相应地更新了.hidden状态,但除非再次保存.tsx文件,否则将不会发生转到.show的动画。
有谁知道是什么导致了这个问题,是因为它是Typescript还是React还是Vit,e以及如何解决这个问题?
还有什么其他的方法可以在不使用外部库的情况下在滚动上动画?
谢谢大家。

qyyhg6bp

qyyhg6bp1#

动画不起作用,因为在渲染零部件之前就观察到了零部件。在useEffect中设置IntersectionObserver,如下所示:

function App() {
  React.useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          entry.target.classList.add("show");
        } else {
          entry.target.classList.remove("show");
        }
      });
    });

    const hiddenElements = document.querySelectorAll(".hidden");
    hiddenElements.forEach((el) => observer.observe(el));
    
    // Clean up the memory before the component gets destroyed:
    return () => {
      hiddenElements.forEach((el) => observer.unobserve(el));
    };
  }, []);
  return (
    <div>
      <p className="sample">Scroll to see annimations</p>
      <p className="hidden">Instruction 1</p>
      <p className="hidden">Instruction 2</p>
      <p className="hidden">Instruction 3</p>
      <div className="hidden">
        <img
          alt=""
          src="https://images.unsplash.com/photo-1682547095701-c6f1daa00c59?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80"
        />
      </div>
    </div>
  );
}

// This is to have a working example here on Stack Overflow:
ReactDOM.render(
  <App />,
  document.getElementById("root")
);
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  padding: 1rem;
}

p {
  background-color: red;
  color: white;
  padding: 1rem;
  border-radius: 1rem;
  min-height: 30vh;
  display: grid;
  place-items: center;
  font-family: sans-serif;
  margin-bottom: 1rem;
}
p:first-of-type {
  background-color: beige;
  color: black;
  min-height: 100vh;
  font-size: 4rem;
  font-weight: bold;
  text-align: center;
}
.hidden {
  transition: all 1.5s;
  opacity: 0.5;
  filter: blur(5px);
  transform: translateX(-100%);
}
.show {
  opacity: 1;
  filter: blur(0);
  transform: translateX(0);
}

img {
  max-width: 100%;
  display: block;
  border-radius: 1rem;
}
<!-- This is to have a working example here on Stack Overflow: -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

相关问题