强制交叉口观察者更新

时间:2018-07-18 13:07:35

标签: 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" : "";
});
#container {
  width: 100px;
  height: 100px;
  background: blue;
  position: relative;
}

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

#red {
  background: red;
  right: -10px;
}
<button>move #red</button>
<br /><br />
<div id="container">
  <div id="green"></div>
  <div id="red"></div>
</div>

有什么办法可以使它起作用?唯一可行的方法是unobserve元素,然后再次启动observing。这可能对单个元素有效,但如果观察者有数百个要监视的元素则不行。

// 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);
});
#container {
  width: 100px;
  height: 100px;
  background: blue;
  position: relative;
}

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

#red {
  background: red;
  right: -10px;
}
<button>move #red</button>
<br /><br />
<div id="container">
  <div id="green"></div>
  <div id="red"></div>
</div>

4 个答案:

答案 0 :(得分:1)

我认为不强制在节点上不调用取消观察/观察就可以强制交叉观察器进行更新,但是您可以通过将所有观察到的节点保存在集合中来对它们进行此操作:

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);
        }
    }
}

编辑:因为SetWeakSet,所以使用iterable代替unobseve,因此无需检查体内每个元素是否都在观察该元素。请小心致电.stream(this.customer1()) .stream(this.customer2()) ,以避免出现内存问题。

答案 1 :(得分:0)

您只需要为交叉口观察者设置threshold: 1.0即可。这是一个难以理解的参数。阈值定义了观察者触发回调的交点的百分比。

默认值为0,这意味着当元素的第一个像素或最后一个像素与捕获帧的边界相交时,将触发回调。您的元素永远不会完全离开捕获帧。这就是为什么永远不会调用回调的原因。

如果将阈值设置为1,则当元素位于帧中100%时,告诉观察者触发回调。这意味着将在此100%包含状态的更改时触发回调。我希望听起来可以理解:)

// 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'), threshold: 1.0 };
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" : "";
});
#container {
  width: 100px;
  height: 100px;
  background: blue;
  position: relative;
}

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

#red {
  background: red;
  right: -10px;
}
<button>move #red</button>
<br /><br />
<div id="container">
  <div id="green"></div>
  <div id="red"></div>
</div>

答案 2 :(得分:-1)

我可能无法正确回答这个问题,据我了解,您想触发IntersectionObserver,因此将调用您的回调。为什么不直接叫它呢?

photo displaying.
       for row in rows:
            photo=row[2]
            img1="images/"+str(photo)+".png"
            img= PhotoImage(file=img1)
            photol= Label(photoframe,image=img,width=150,height=100)
            photol.pack()

            
            
            
            


                            
            

答案 3 :(得分:-2)

一种方法是使用MutationObserver。如果发生突变(在这种情况下为样式更改),则对已更改的元素调用观察/取消观察。这样,您不必对所有元素都这样做。

这里是一个例子:

// 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);

const boxes = document.querySelectorAll('#container > div');
boxes.forEach(box => {
  observer.observe(box);
});

// button action
document.querySelector('button').addEventListener('click', () => {
  red.style.right = red.style.right == "" ? "0px" : "";
});



// Mutation observer
const targetNode = document.querySelector('#container');

// Options for the observer (which mutations to observe). We only need style changes so we set attributes to true. Also, we are observing the children of container so subtree is true
const config = {
  attributes: true,
  childList: false,
  subtree: true,
  attributeFilter: ["style"]
};

// Callback function to execute when mutations are observed
const mutationCallback = (mutationsList, mutationObserver) => {
  for (let mutation of mutationsList) {
    if (mutation.type === 'attributes') {
      console.log('The ' + mutation.attributeName + ' attribute was modified.');
      observer.unobserve(mutation.target);
      observer.observe(mutation.target);
    }
  }
};

// Create an observer instance linked to the callback function
const mutationObserver = new MutationObserver(mutationCallback);

// Start observing the target node for configured mutations
mutationObserver.observe(targetNode, config);
#container {
  width: 300px;
  height: 300px;
  background: lightblue;
  position: relative;
}

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

#red {
  background: purple;
  right: -10px;
}
<button>move #red</button>
<br /><br />
<div id="container">
  <div id="green"></div>
  <div id="red"></div>
</div>