Каждый новый анимированный элемент с IntersectionObserver получает нежелательную задержку - PullRequest
2 голосов
/ 22 марта 2020

Я использую IntersectionObserver для анимации каждого h1 при прокрутке. Проблема, как вы можете видеть из фрагмента, состоит в том, что анимация срабатывает каждый раз для каждого h1. Это означает, что каждая новая анимация пересекающегося h1 должна ждать завершения предыдущих анимаций, и результат в основном является своего рода дополнительной задержкой для каждого нового entry.target. Это не то, что я хочу. Я пытался удалить класс anim-text до и после отмены наблюдения entry.target, но это не сработало. Я думаю, что проблема в forEach l oop внутри секции // ТЕКСТОВОЕ РАЗДЕЛЕНИЕ, но все мои усилия не решили эту проблему.

Заранее благодарим за помощь!

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>

1 Ответ

1 голос
/ 22 марта 2020

Давайте немного упростим здесь, потому что вы показываете больше кода, чем необходимо. Кроме того, вы делаете некоторые вещи немного странным образом, поэтому несколько советов.

  1. У вас есть if (...) { return } else ..., для которого не требуется else область видимости: либо функция возвращается, либо мы просто продолжаем.
  2. Вместо того, чтобы проверять «не пересекается» и затем возвращаться, вместо этого проверяют вставку и затем запускают.
  3. Вы используете композицию строк, используя +: прекратите использовать это и начните использовать современные шаблонные строки. Поэтому вместо "a" + b + "c" вы используете `a${b}c`. Нет больше +, больше нет ошибок, связанных с составлением строки.
  4. Вы используете назначение .innerHTML: это невероятно опасно, особенно если чужой скрипт обновил ваш заголовок до буквального HTML кода, подобного image или что-то в этом роде. Никогда не используйте innerHTML, используйте обычные функции DOM (createElement, appendChild и т. Д. c).
  5. Вы использовали много const thing = arrow function без необходимости сохранения this: просто делайте эти нормальные функции и извлекайте выгоду из подъема (все нормальные функции связаны с областью действия до , когда любой код фактически запускается)
  6. При использовании обозревателя, unobserver до вы Запустите код, который нужно включить для наблюдаемой записи, особенно если вы запускаете более нескольких строк кода. Это не доказательство глупости, но значительно снижает вероятность того, что ваш вход во второй раз будет повторяться, когда люди быстро проведут пальцем или прокрутят ваш элемент.
  7. И, наконец, причина, по которой ваш код не сработал: Вы выбираете все .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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...