Давайте немного упростим здесь, потому что вы показываете больше кода, чем необходимо. Кроме того, вы делаете некоторые вещи немного странным образом, поэтому несколько советов.
- У вас есть
if (...) { return } else ...
, для которого не требуется else
область видимости: либо функция возвращается, либо мы просто продолжаем. - Вместо того, чтобы проверять «не пересекается» и затем возвращаться, вместо этого проверяют вставку и затем запускают.
- Вы используете композицию строк, используя
+
: прекратите использовать это и начните использовать современные шаблонные строки. Поэтому вместо "a" + b + "c"
вы используете `a${b}c`
. Нет больше +
, больше нет ошибок, связанных с составлением строки. - Вы используете назначение
.innerHTML
: это невероятно опасно, особенно если чужой скрипт обновил ваш заголовок до буквального HTML кода, подобного или что-то в этом роде. Никогда не используйте innerHTML
, используйте обычные функции DOM (createElement
, appendChild
и т. Д. c). - Вы использовали много
const thing = arrow function
без необходимости сохранения this
: просто делайте эти нормальные функции и извлекайте выгоду из подъема (все нормальные функции связаны с областью действия до , когда любой код фактически запускается) - При использовании обозревателя, unobserver до вы Запустите код, который нужно включить для наблюдаемой записи, особенно если вы запускаете более нескольких строк кода. Это не доказательство глупости, но значительно снижает вероятность того, что ваш вход во второй раз будет повторяться, когда люди быстро проведут пальцем или прокрутят ваш элемент.
- И, наконец, причина, по которой ваш код не сработал: Вы выбираете все
.anim-text span
элементов. Включая заголовки, которые вы уже обработали. Поэтому, когда второй прокручивается в поле зрения, вы выбираете все span
в обоих в первом и втором заголовках, а затем пошагово анимируете их буквы. Вместо этого вам нужно только разбить буквы в текущем заголовке, поэтому задайте им id
и затем выберите запрос, используя вместо этого #headingid span
.
Однако, хотя 7 звучит как исправление, спасибо к тому, как работает современный текст, у вас все еще есть потенциальная ошибка: нет гарантии, что слово выглядит так же, как «набор букв, из которых он состоит», из-за лигатур. Например, если вы используете шрифт, имеющий лигатуру, которая превращает фактическую строку =>
в один глиф ⇒
(как это делают несколько программных шрифтов), тогда ваш код будет делать совсем не то.
Но это не обязательно то, что нужно исправить прямо сейчас, больше о чем нужно помнить. Ваш код не всегда работает, но он может быть достаточно хорош для ваших целей.
Итак, после всего этого давайте немного перепишем ваш код, отбросим части, которые не являются действительно имеет отношение к проблеме, и, конечно, самое главное, исправить вещи:
function revealEntry(h1) {
const text = h1.textContent;
h1.textContent = "";
text.split(``).forEach(part => {
const span = document.createElement('span');
span.textContent = part;
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;
observer.unobserve(h1);
revealEntry(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>