强制 IntersectionObserver 更新

eis*_*ehr 21 javascript intersection-observer

有没有办法强制更新/运行IntersectionObserver实例?当视口发生变化时,回调将默认执行。但是我正在寻找一种在其他事件发生时执行它的方法,比如元素的变化。

一个例子:

初始化时一切正常。但是当你改变#red元素的位置时,什么也没有发生。

// elements
let green = document.querySelector('#green');
let red = document.querySelector('#red');

// observer callback
let callback = entries => {
  entries.forEach(entry => {
    let isInside = entry.intersectionRatio >= 1 ? "fully" : "NOT";
    console.log("#" + entry.target.id + " is " + isInside + " inside #container");
  });
};

// start observer
let options = {root: document.querySelector('#container')};
let observer = new IntersectionObserver(callback, options);
observer.observe(green);
observer.observe(red);

// button action
document.querySelector('button').addEventListener('click', () => {
  red.style.right = red.style.right == "" ? "0px" : "";
});
Run Code Online (Sandbox Code Playgroud)
#container {
  width: 100px;
  height: 100px;
  background: blue;
  position: relative;
}

#green, #red {
  width: 50px;
  height: 50px;
  background: green;
  position: absolute;
}

#red {
  background: red;
  right: -10px;
}
Run Code Online (Sandbox Code Playgroud)
<button>move #red</button>
<br /><br />
<div id="container">
  <div id="green"></div>
  <div id="red"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

有什么办法可以使这个工作吗?唯一可行的是unobserve元素并重新启动observing它。这可能适用于单个元素,但不适用于 Observer 有数百个元素要观看的情况。

// elements
let green = document.querySelector('#green');
let red = document.querySelector('#red');

// observer callback
let callback = entries => {
  entries.forEach(entry => {
    let isInside = entry.intersectionRatio >= 1 ? "fully" : "NOT";
    console.log("#" + entry.target.id + " is " + isInside + " inside #container");
  });
};

// start observer
let options = {root: document.querySelector('#container')};
let observer = new IntersectionObserver(callback, options);
observer.observe(green);
observer.observe(red);

// button action
document.querySelector('button').addEventListener('click', () => {
  red.style.right = red.style.right == "" ? "0px" : "";
  observer.unobserve(red);
  observer.observe(red);
});
Run Code Online (Sandbox Code Playgroud)
#container {
  width: 100px;
  height: 100px;
  background: blue;
  position: relative;
}

#green, #red {
  width: 50px;
  height: 50px;
  background: green;
  position: absolute;
}

#red {
  background: red;
  right: -10px;
}
Run Code Online (Sandbox Code Playgroud)
<button>move #red</button>
<br /><br />
<div id="container">
  <div id="green"></div>
  <div id="red"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

Isi*_*osa 1

我认为不可能在不调用节点上的 unobserve/observe 的情况下强制相交观察器更新,但是您可以通过将所有观察到的节点保存在一个集合中来对它们执行此操作:

class IntersectionObserverManager {
    constructor(observer) {
        this._observer = observer;
        this._observedNodes = new Set();
    }
    observe(node) {
        this._observedNodes.add(node);
        this._observer.observe(node);
    }
    unobserve(node) {
        this._observedNodes.remove(node);
        this._observer.unobserve(node);
    }
    disconnect() {
        this._observedNodes.clear();
        this._observer.disconnect();
    }
    refresh() {
        for (let node of this._observedNodes) {
            this._observer.unobserve(node);
            this._observer.observe(node);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:使用 aSet而不是 a,WeakSet因为它们是iterable这样,因此无需检查主体中的每个元素是否正在观察该元素。调用unobseve时要小心,以免出现内存问题。