IntersactionObserver() отслеживает только первый элемент строки, а не все

#javascript #intersection-observer

#javascript #пересечение-наблюдатель

Вопрос:

Я экспериментирую с IntersectionObserver(), и он ведет себя странно: я использую очень простой макет, всего 8 изображений в одном div с flexbox, используя wrap, так что в основном 8 изображений располагаются в разных строках в зависимости от размера области просмотра. Сначала я применяю класс filter (который добавляет фильтр размытия) к каждому элементу, а затем удаляю его, когда они отображаются на экране:

HTML:

 <div class="flex--cont">
            <div class="box box-2">
                <img src="img/1.jpg" alt="" class="img img-1">
            </div>
            <div class="box box-1">
                <img src="img/2.jpg" alt="" class="img img-2">
            </div>
            <div class="box box-3">
                <img src="img/3.jpg" alt="" class="img img-3">
            </div>
            <div class="box box-4">
                <img src="img/4.jpg" alt="" class="img img-4">
            </div>
            <div class="box box-5">
                <img src="img/5.jpg" alt="" class="img img-5">
            </div>
            <div class="box box-6">
                <img src="img/6.jpg" alt="" class="img img-6">
            </div>
            <div class="box box-7">
                <img src="img/7.jpg" alt="" class="img img-7">
            </div>
            <div class="box box-8">
                <img src="img/8.jpg" alt="" class="img img-8">
            </div>
        </div>
 

JAVASCRIPT

 const allImage = Array.from(document.querySelectorAll(".img"));
allImage.forEach((img) => img.classList.add("filter"));

const removeFilter = function (entries, observer) {
  const [entry] = entries;
  const image = entry.target;
  image.classList.remove("filter");
};

const ImageObserver = new IntersectionObserver(removeFilter, {
  root: null,
  threshold: 0.15,
});

allImage.forEach((img) => ImageObserver.observe(img));
 

Дело в том, что наблюдатель фактически наблюдает только самый первый элемент каждой строки, поэтому, если у меня 2 строки, он получает только 1-е и 5-е изображение, если у меня 3 строки, он получает 1-е, 4-е и 7-е изображения и так далее. Я применил его ко всем изображениям. Почему он это делает? Спасибо за ваши ответы!

Комментарии:

1. Не могли бы вы воспроизвести эту проблему в stackblitz?

2. Я попробую. Я скоро опубликую его👍

3. Я сделал это в codepen, но это показывает проблему. Я хочу, чтобы весь квадрат стал синим, но только первый из каждой строки становится синим codepen.io/andreauge/pen/ExgYqVB

Ответ №1:

Менялся только первый, потому что это было все, на что вы нацеливались в функции изменения цвета, разрушая только первый элемент массива:

const [entry] = entries;

Однако InteractionObserver обратный вызов вызывается не для каждой записи, а для всех записей, которые запускаются одновременно; следовательно entries , массив содержит все наблюдаемые элементы, и вам нужно проверить isIntersecting свойство следующим образом:

 const changeColor = function(entries) {
  entries.forEach(entry => {
    if(entry.isIntersecting) {
      entry.target.style.background = 'blue';
    } else {
      entry.target.style.background = 'red';
    }
  })
}
 

Из документов MDN

 let callback = (entries, observer) => {
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};
 

Комментарии:

1. Ну, это очень полный и прямой ответ. Большое тебе спасибо, Эндрю!