浏览器加载时立即触发IntersectionObserver回调函数

55

我对IntersectionObserver API非常陌生,并且我一直在试验这段代码:

let target = document.querySelector('.lazy-load');

let options = {
    root: null,
    rootMargin: '0px',
    threshold: 0
}

let observer = new IntersectionObserver(callback, options);

observer.observe(target);

function callback() {
    console.log('observer triggered.');
}

这似乎按照预期工作,当.lazy-load元素进入视口时会调用callback(),但是callback()在页面初始加载时也会触发一次,这将触发`console.log('观察器已触发。');

这个回调函数在页面加载时被触发有原因吗?或者我实现的方式有误吗?

编辑:将代码更改为以下内容仍会在页面加载时触发回调。

let target = document.querySelector('.lazy-load');

let options = {
    root: null,
    rootMargin: '0px',
    threshold: 0
}

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

        console.log('observer triggered.');

    });
};

let observer = new IntersectionObserver(callback, options);

observer.observe(target);

我有一个类似的问题,但阈值为1。所以这里的答案不适用。 - Tofandel
2个回答

80

这是默认行为。当您实例化IntersectionObserver的一个实例时,会触发callback

建议防范此情况。

entries.forEach(entry => {
  if (entry.intersectionRatio > 0) {
    entry.target.classList.add('in-viewport');
  } else {
    entry.target.classList.remove('in-viewport');
  }
});
我发现这篇文章和相关文档对于IntersectionObserverEntry的intersectionRatioisIntersecting属性非常有帮助。以下是相关链接:

· https://www.smashingmagazine.com/2018/01/deferring-lazy-loading-intersection-observer-api/

· https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver

· https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry


很棒的回答,谢谢。 - rpivovar
10
我认为更好依赖于 isIntersecting,因为有时候我看到一些情况下 intersectingRatio 是零但是 isIntersecting 是真的 --- 在我的情况下这是正确的行为。 - zenw0lf
1
@zenw0lf 很好的观点!这就是我在这里做的... https://github.com/snewcomer/intersection-observer-admin/blob/28b25180c231b09c61239b6440e8f48a345ea808/src/index.ts#L229 - snewcomer
很遗憾,当元素与case不相交时,你无法使用 .unobserve() 来取消观察该元素。只能使用一些丑陋的变更器来标记元素是否已经在视口中。 - Dr. Freddy Dimethyltryptamine
当您实例化IntersectionObserver的实例时,回调将被触发。我的理解是,当您第一次调用新IntersectionObserver的observe方法时,它会调用回调函数。如果您有一个按钮来调用observe方法,那么它应该异步地调用IntersectionObserver。 - JoePythonKing
你好,@snewcomer,能否帮我看一下我的问题?https://dev59.com/2dL7oIgBc1ULPQZFnzVN - Sophie

3

听起来很容易,我能够通过以下方式解决这个问题:

  1. 添加阈值比较条件
  2. 为观察者的初始化添加轻微延迟
    const options = {
      threshold: 1.0,
    };

      setTimeout(() => {
        observer = new IntersectionObserver(([entry]) => {
          console.log("OBSERVER TRIGGERED 1");

          if (
            entry &&
            entry.isIntersecting &&
            entry.intersectionRatio >= options.threshold
          ) {
            console.log("OBSERVER TRIGGERED 2");
          }
        }, options);

        observer.observe(observerRef.value);
      }, 2000);

我建议将可观察元素的背景颜色临时更改为以下类似颜色:
.observer {
  background-color: red;
}

并进行页面刷新。这样你可能会在屏幕上看到红色背景闪烁,从而触发事件。

现在,在你扔番茄之前 - 在我的情况下 - 我的网页上有十几个视频。视频HTML元素不会立即“展开”,因为浏览器需要下载海报图像的信息。因此,页面已加载,但视频仍在逐个加载.. 添加轻微延迟可解决问题,以便浏览器有时间扩展视频内容。


你好,@alex,能否帮我看一下我的问题?https://dev59.com/2dL7oIgBc1ULPQZFnzVN - Sophie
给它一个红色背景真是个绝妙的点子。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接