【问题标题】:Same intersection observer for multiple HTML elements多个 HTML 元素的相同交集观察者
【发布时间】:2019-02-25 12:46:56
【问题描述】:

我正在尝试使某些文本项停止与深色背景重叠,它们将在用户滚动时逐个更改颜色。所有的文本项都是position: fixed

编辑:MDN 文档说(强调我的):

Intersection Observer API 提供了一种异步观察的方法 目标元素与 祖先 的交集的变化 元素

我认为这意味着没有办法解决我的问题,因为我要监视重叠的元素不是我在选项对象中指定的 root 的子元素。

如果重叠元素不是另一个元素的子元素,有什么方法可以检测重叠?

if ('IntersectionObserver' in window) {

    const options = {
        root: document.getElementById('flow-landing'),
        rootMargin: '0px',
        threshold: 0
      }


    var callback = function(entries, observer) { 
            entries.forEach(entry => {

                if (entry.isIntersecting) {
                    entry.target.style.color = "white";
                }
                else {
                    entry.target.style.color = null;
                }
            });
          };

    const observer = new IntersectionObserver(callback, options);

    var targets = [Array.from(document.querySelectorAll('.social-item')), Array.from(document.querySelectorAll('.additional-item'))].flat();

    targets.forEach(target => 
        observer.observe(target));
}

没有任何控制台错误,但代码没有做任何事情。

【问题讨论】:

  • 来自 MDN 的完整引用如下:"Intersection Observer API 提供了一种异步观察目标元素与祖先元素或顶部元素的交集变化的方法级文档的视口。”document.getElementById('flow-landing') 替换为 null。将整篇文章至少阅读两次,因为有时很难将解释形象化。

标签: javascript intersection-observer


【解决方案1】:

稍微修改 Ruslan 的回答,因为在他的回答中,正在创建多个 Intersection Observer 对象。

通过在多个元素上调用.observe(),可以使用同一个观察者观察多个元素。

let observerOptions = {
    rootMargin: '0px',
    threshold: 0.5
}

var observer = new IntersectionObserver(observerCallback, observerOptions);

function observerCallback(entries, observer) {
    entries.forEach(entry => {
        if(entry.isIntersecting) {
          //do something
        }
    });
};

let target = '.targetSelector';
document.querySelectorAll(target).forEach((i) => {
    if (i) {
        observer.observe(i);
    }
});

【讨论】:

  • 这种方法在性能方面有什么缺点吗? (在多个元素上使用观察者)
【解决方案2】:

你可以这样做,至少它对我有帮助:

document.querySelectorAll('.social-item').forEach((i) => {
    if (i) {
        const observer = new IntersectionObserver((entries) => {
            observerCallback(entries, observer, i)
        },
        {threshold: 1});    
        observer.observe(i);
    }
})

const observerCallback = (entries, observer, header) => {
    entries.forEach((entry, i) => {
         if (entry.isIntersecting) {
             entry.target.style.color = "white";
         }
         else {
             entry.target.style.color = null;
         }
    });
};

【讨论】:

  • 您好,谢谢您 - 这正是我一直在寻找的。但我正在努力让它发挥作用。你能告诉我你的例子中的“条目”是什么吗?是固定社交项下滚动的对象吗?
  • @ToddPadwick 这里是目标 '.social-item' DOM 项目
【解决方案3】:

您可以使用offsetTopoffsetHeight 属性代替IntersectionObserver API。

例如,当用户滚动时,您可以检查element 2offsetTop 是否大于offsetTop 并且小于element 1offsetHeight

警告:使用 debounce,因为滚动事件的处理函数将为用户滚动的每个像素调用一次,想象一下性能噩梦如果用户滚动 600-1000 像素,就会发生这种情况。

LoDash documentationit's debounce function 描述为:

“[一个函数] 创建一个去抖动函数,该函数延迟调用 func(处理程序)直到 wait(时间)自上次调用去抖动函数后经过毫秒。”

如果你不使用 LoDash,这里有一个 Vanilla JavaScript debounce 函数:

function debounce(handler, time) {
  var timeout;
  return function() {
    var self = this, args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      return handler.apply(self, args);
    }, time);
  };
}

如果element 2 “intersects” element 1,这是允许您“做事”的代码。

let element_1 = document.querySelector("#my-element-1");
let element_2 = document.querySelector("#my-element-2");
window.addEventListener("scroll", debounce(() => {
  if(element_2.offsetTop > element_1.offsetTop && element_2.offsetTop < element_1.offsetHeight) {
    console.log("The elements are intersecting.");
  }
}, 100));

如果看起来复杂或难以阅读,这里是相同的代码,被分成更小的块:

let element_1 = document.querySelector("#my-element-1");

let element_2 = document.querySelector("#my-element-2");

window.addEventListener("scroll", debounce(() => {

  let x = element_2.offsetTop > element_1.offsetTop;

  let y = element_2.offsetTop < element_1.offsetHeight;

  if(x && y) {

    console.log("The elements are intersecting.");

  }

}, 250));

注意事项和信息:

  1. 您可以使用&gt;=&lt;= 运算符代替&gt;&lt; 运算符
  2. wait 时间过长可能会使效果看起来不自然和强制。

祝你好运。

【讨论】:

  • Intersection Observer API 取代了您提到的方法,因为监听滚动事件是同步完成的,因此它是阻塞的且性能较低
猜你喜欢
  • 2017-06-04
  • 1970-01-01
  • 2021-04-13
  • 1970-01-01
  • 2022-01-20
  • 2019-04-17
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
相关资源
最近更新 更多