Intersection Observer: вызывать функцию только один раз для каждого элемента

Я использую Intersection Observer API для отслеживания видимости нескольких элементов на веб-странице. Когда элемент становится видимым, функция callback() должно быть выполнено. Ограничение: для каждого элемента функция может быть выполнена только один раз.

Вот моя текущая реализация для проекта веб-аналитики:

const elements = document.querySelectorAll('[data-observable]');
const callback = str => { console.log(str); };
const observer = new IntersectionObserver(handleIntersection);

elements.forEach(obs => {
  observer.observe(obs);
});

function handleIntersection(entries, observer){
  entries.forEach(entry => {
    if (entry.intersectionRatio > 0) {
      // Call this function only once per element, without modifying entry object
      callback('observer-' + entry.target.getAttribute('data-observable'));
    }
  });
}

Я изо всех сил пытаюсь найти решение, которое не изменяет существующие элементы, IntersectionObserver или IntersectionObserverEntries.

Обычно я использовал бы замыкание, чтобы гарантировать, что функция выполняется только один раз:

function once(func) {
  let executed = false;
  return function() {
    if (!executed) {
      executed = true;
      return func.apply(this, arguments);
    }
  };
}

Но в этом случае у меня возникают трудности с применением функции, потому что IntersectionObserver использует странную логику итератора обратного вызова, которая выполняется каждый раз, когда изменяется любой элемент (вместо использования модели, управляемой событиями).

Любые идеи, как реализовать вызов функции один раз на элемент, который не изменяет другие элементы или объекты?

0 ответов

Как отметил james.brndwgn в комментариях, самое простое решение этой проблемы - это не заметить элемент, как только он станет видимым и будет вызван обратный вызов.

const elements = document.querySelectorAll('[data-observable]');
const callback = str => { console.log(str); };
const observer = new IntersectionObserver(handleIntersection);

elements.forEach(obs => {
  observer.observe(obs);
});

function handleIntersection(entries, observer){
  entries.forEach(entry => {
    if (entry.intersectionRatio > 0) {
      callback('observer-' + entry.target.getAttribute('data-observable')); 
      observer.unobserve(entry.target);
    }
  });
}

Я не нашел какого-либо жизнеспособного решения использовать замыкание, чтобы контролировать, как часто можно вызывать функцию.

Другие вопросы по тегам