IntersectionObserver不能在回调中的目标上工作吗?

问题描述

我正在尝试在用户向下滚动时向页面添加元素。当最后一个元素完全显示时,我希望调用观察者回调,创建一个新元素,观察者设置为观察新元素,而不再观察当前目标。

function observerCallback(entries,observer) {
  entries.forEach((entry) => {
    const newDiv = document.createElement('div')
    observer.observe(newDiv)
    document.body.appendChild(newDiv)
    observer.unobserve(entry.target);
  });
}

但是,这不起作用,而且回调一直不断被调用,并产生了新的元素。我设置了一个codepen来演示此问题。

为什么会这样?

解决方法

您必须检查entry是否可见(与容器相交)

if (entry.isIntersecting) {
   //...
}

只有这样(或者如果阈值高于某个值),就会向DOM添加一个新元素。

let observer = new IntersectionObserver(observerCallback,{ threshold: 1.0 });

function observerCallback(entries,observer) {
  entries.forEach((entry) => {
    if (!entry.isIntersecting) {
      return;
    }

    const newDiv = document.createElement('div')
    observer.observe(newDiv)
    document.body.appendChild(newDiv)
    observer.unobserve(entry.target);
  });
}

observer.observe(document.querySelector('div'))
div { height: 50px; background-color: red; margin-bottom: 20px }
<div></div>

,

仅仅是调用IntersectionObserver.observe(target)会触发该target的回调。

const observer = new IntersectionObserver(entries => {
  console.log( 'new entry!',entries[0].target );
});
// wait a bit to show that it's really the call to observe() that does trigger the callback
setTimeout(()=> {
  // even if not attached
  const elem = document.createElement('div');
  observer.observe( elem );
},2000);

所以unobserve可以很好地工作,只是新观察到的元素本身会触发新的回调调用。

不知道您到底想做什么,很难告诉您如何修复代码,但这应该可以帮助您找到正确的路线,也许您只是在寻找isIntersecting属性,因此当不再显示最后一个元素时停止。

let observer = new IntersectionObserver(observerCallback,observer) {
  entries.forEach((entry) => {
    if( !entry.isIntersecting ) {
      return;
    }
    const newDiv = document.createElement('div')
    observer.observe(newDiv)    
    document.body.appendChild(newDiv)
    observer.unobserve(entry.target);
  });
}

observer.observe(document.querySelector('div'))
div {
  height: 20px;
  background-color: red;
  margin-bottom: 5px;
}
<div></div>

,

这仅仅是您执行功能的顺序吗?由于某些原因,CodePen无法在我的iPad上运行,因此我暂时无法测试。

function observerCallback(entries,observer) {
  entries.forEach((entry) => {
    const newDiv = document.createElement('div')
    observer.unobserve(entry.target)
    document.body.appendChild(newDiv)
    observer.observe(newDiv)
  });
}