ResizeObserver

ResizeObserver

Chrome 在 54 版本中新增了 ResizeObserver API,用于观察元素大小的变化并触发对应的回调事件。

之前,我们通过 window.resize() 来监听窗口的变化,但无法具体到 DOM 元素的变化。另外,resize 事件触发过于频繁容易影响性能,而且也无法监听到元素的新增或删除。

1
2
3
4
5
window.addEventListener('resize', () => {
const box = element.getBoundingClientRect();

...
})

语法

1
2
3
4
5
6
[Constructor(ResizeObserverCallback callback), Exposed=Window]
interface ResizeObserver {
void observe(Element target);
void unobserve(Element target);
void disconnect();
};
  • new ResizeObserver(callback)

    创建 ResizeObserver 对象

  • observe(target)

    添加待观察元素

  • unobserve(target)

    将元素从观察目标列表中移除

  • disconect()

    清空观察目标列表以及激活目标(目标元素发生变化但未执行回调)列表

1
2
3
4
5
6
7
const observer = new ResizeObserver(entries => {
entries.forEach(entry => {
const { contentRect, target } = entry;
})
});

observer.observe(element)

元素发生变化时会触发回调,并返回变化后的 entry 对象。entry 中包含 contentRecttarget 属性。

target 指向元素本身,contentRect 对象包含了元素变化后的:widthheightxytoprightbottomleft 属性。widthheight 属性指元素 content 区域的宽高,并不包含 padding 和 margin;toprightbottomleft 指元素的 padding 值。

对于以下情况,ResizeObserver 有不一样的处理:

  • 元素的插入、删除会触发回调
  • 元素 display 值设为 none 时,会触发回调
  • 非替换内联元素(non-replaced inline element)不会触发回调
  • 由 CSS transform 引发的元素变化不会触发回调
  • 由默认显示且大小不为 0 的元素发生的变化会触发回调

Demo

扩展

在 ResizeObserver 回调中再次改变元素,则会再次触发回调函数,那这样是否会导致无限回调循环呢? 答案是否,因为 ResizeObserver 存在一种机制可以避免无限回调以及循环依赖。

Changes will only be processed in the same frame if the resized element is deeper in the DOM tree than the shallowest element processed in the previous callback. Otherwise, they’ll get deferred to the next frame.

PS:尝试翻译了下,感觉词不达意,还是引用原文的好。((ノへ ̄、)捂脸)

兼容性

目前仅有 Chrome 54+ 支持,而且需要开启该特性。

补充

参考