为啥引入 `ResizeObserver` 来监听调整大小的变化,而不是更简单的 Element.prototype.addEventListener('resize', callback)
Posted
技术标签:
【中文标题】为啥引入 `ResizeObserver` 来监听调整大小的变化,而不是更简单的 Element.prototype.addEventListener(\'resize\', callback)【英文标题】:why was `ResizeObserver` introduced to listen to resize changes and not a simpler Element.prototype.addEventListener('resize', callback)为什么引入 `ResizeObserver` 来监听调整大小的变化,而不是更简单的 Element.prototype.addEventListener('resize', callback) 【发布时间】:2018-06-13 18:03:49 【问题描述】:我有点惊讶,为了监听元素尺寸(不是窗口对象)的变化,我们必须使用一个名为ResizeObserver
的新接口。虽然它似乎做得很好;这似乎与仅添加侦听器即可使用的其他元素相关事件有所不同。
例如添加一个事件监听器来监听鼠标悬停事件
document.querySelector('#ele').addEventListener('mouseover', callback);
为什么不简单地为元素的 resize 事件添加一个新的侦听器?
document.querySelector('#ele').addEventListener('resize', callback);
是为了避免与窗口resize
事件发生冲突吗?如果是这样,为什么不换个名字来称呼它
document.querySelector('#ele').addEventListener('elementResize', callback);
我知道创建一个帮助方法来简化ResizeObserver
的使用很容易。这样的东西可以像原来的 addEventListener
方法一样简单使用
export const getResizeObserver = ( ele, onResize ) =>
let obs;
const observerInterface =
stop: () => obs.unobserve( ele ); obs.disconnect() ,
;
obs = new ResizeObserver( entries =>
for ( const entry of entries )
onResize && onResize( entry.contentRect );
);
obs.observe( ele );
return observerInterface;
;
// usage to add the listener
const obs = getResizeObserver(document.querySelector('#ele'), callback);
// later to remove the listener
obs.stop();
在任何情况下,除了 api 偏好和多个元素可以共享观察者实例这一事实之外,还有什么理由使 ResizeObserver
方法比 addEventListener
方法更好?
【问题讨论】:
【参考方案1】:有一个讨论 in this PR,其中 W3C 技术架构小组试图定义何时使用观察者模式而不是 EventTarget。此讨论的输出记录在here,我引用了第一条声明:
一般来说,使用 EventTarget 和通知事件,而不是 观察者模式,除非 EventTarget 不能很好地为你工作 功能。
使用观察者模式相对于EventTarget 的优势如下:
可以在观察时或创建时自定义实例。 Observer 的构造函数或其
observe()
方法可以采用允许作者自定义每个回调观察到的内容的选项。addEventListener()
无法做到这一点。使用 Observer 对象上的
disconnect()
或unobserve()
方法很容易停止监听多个回调。您可以选择提供类似
takeRecords()
的方法,该方法会立即获取相关数据,而不是等待事件触发。因为观察者是单一用途的,所以您不需要指定事件类型。
具体谈谈ResizeObserver
,在我看来:
第 2 点和第 4 点不太相关。它没有添加或占用任何关键的东西,我认为resize
事件在这里会更好。
它仍然没有实现takeRecords()
方法,所以3d点无关
它使我们能够在创建和观察时对其进行自定义,并允许稍后更改这些自定义 API,而无需更改 Event 模型。
另外,可能存在性能问题或an unavoidable recursion,但我没有找到任何关于它们的测量或解释。
【讨论】:
【参考方案2】:这是proposed(问题仍然存在),但 Chrome 决定使用观察者模型来发布它,似乎主要是因为它比基于事件的实现快 10 倍 https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/z6ienONUb5A
现在为什么那是真的,我不知道。
【讨论】:
以上是关于为啥引入 `ResizeObserver` 来监听调整大小的变化,而不是更简单的 Element.prototype.addEventListener('resize', callback)的主要内容,如果未能解决你的问题,请参考以下文章
如何使用反应测试库模拟 ResizeObserver 以在单元测试中工作