@4lolo/resize-observer-polyfill 中文文档教程
ResizeObserver Polyfill
Resize Observer API 的 polyfill。
实现基于 MutationObserver,如果不支持第一个事件,则使用 Mutation Events 作为后备,因此除非 DOM 发生变化,否则不会进行轮询。 不修改观察到的元素。 处理 CSS 转换/动画,并可能观察由动态 CSS 伪类引起的变化,例如 :hover
。
遵循 规范 和本机实现。 压缩和 gzip 后大小为 2.44 KiB。
现场演示(在 IE10 及更低版本中存在样式问题)。
Installation
来自 NPM:
npm install resize-observer-polyfill --save-dev
~~来自 Bower:~~(将在下一个主要版本中删除)
bower install resize-observer-polyfill --save-dev
Browser Support
Polyfill 已经在以下浏览器中进行了测试:
< img src="https://saucelabs.com/browser-matrix/que-etc.svg" alt="Build Status">
注意: Internet Explorer 8 及其早期版本是不支持。
Usage Example
建议以 ponyfill 的形式使用此库,这样不会对全局对象造成修改。
import ResizeObserver from 'resize-observer-polyfill';
const ro = new ResizeObserver((entries, observer) => {
for (const entry of entries) {
const {left, top, width, height} = entry.contentRect;
console.log('Element:', entry.target);
console.log(`Element's size: ${ width }px x ${ height }px`);
console.log(`Element's paddings: ${ top }px ; ${ left }px`);
}
});
ro.observe(document.body);
包的主文件是一个 ES5 UMD 包,对于那些知道 module 字段,例如 Rollup< /a> 或 webpack 2+。
注意:全局版本的 polyfill (dist/ResizeObserver.global
) 已弃用,将在下一个主要版本中删除。
Observation Strategy
如上所述,此实现主要(但不完全)依赖于 Mutation Observer,并回退到 IE 9 和 IE 10
的 Mutation Events。说到 Mutation Events 作为回退方法:它们可能不像呈现的那样丑陋,特别是当他们的调用被分批处理、节流并且不需要分析变化时。 鉴于此,它们不会中断浏览器的回流/重绘周期(与 MutationObserver 相同),甚至可能优于 Internet Explorer 的 MO 实现,几乎不会导致性能下降。 在现代浏览器(Chrome、Firefox 等)中,Mutation Observer 减慢了包含 200 次添加/删除元素迭代的套件,更改属性和修改文本数据不到 1%。 Internet Explorer 给出了不同的结果,MO 将同一套件的速度降低了 2-3%,而 Mutation Events 显示的差异约为 0.6%。
至于其他方法(即 iframe/object 和 scroll
策略)被排除的原因:
- They require the observed element to be non-statically positioned.
- You can't apply them directly to quite a number of elements:
<img>
,<input>
,<textarea>
,<canvas>
,<tr>
,<tbody>
,<thead>
,<table>
, etc. For most of them you would need to keep an extra<div>
wrapper and almost all instances of the SVGGraphicsElement will be out of scope. - The ResizeObserver spec requires to deliver notifications when a non-empty visible element becomes hidden, i.e. when either this element directly or one of its parent nodes receive the
display: none
state. Same goes for when it's being removed from or added to the DOM. It's not possible to handle these cases merely by using former approaches, so you'd still need to either subscribe for DOM mutations or to continuously check the element's state.
虽然每种方法都有其自身的局限性,但我认为这太过分了-在构建 polyfill 时关闭这些约束。
Limitations
- Notifications are delivered ~20ms after actual changes happen.
- Changes caused by dynamic pseudo-classes, e.g.
:hover
and:focus
, are not tracked. As a workaround you could add a short transition which would trigger thetransitionend
event when an element receives one of the former classes (example). - Delayed transitions will receive only one notification with the latest dimensions of an element.
Building and Testing
构建 polyfill。 在 dist
文件夹中创建 UMD 包:
npm run build
运行代码风格测试:
npm run test:lint
运行单元测试:
npm run test:spec
在 karma 配置文件中不存在的浏览器中进行
npm run test:spec:custom
测试:针对本机实现进行测试:
npm run test:spec:native
注意: 在调用 spec:native
和 spec:custom
命令后前往 http://localhost:9876/debug.html
页。
ResizeObserver Polyfill
A polyfill for the Resize Observer API.
Implementation is based on the MutationObserver and uses Mutation Events as a fall back if the first one is not supported, so there will be no polling unless DOM changes. Doesn't modify observed elements. Handles CSS transitions/animations and can possibly observe changes caused by dynamic CSS pseudo-classes, e.g. by :hover
.
Follows the spec and the native implementation. The size is 2.44 KiB when minified and gzipped.
Live demo (has style problems in IE10 and lower).
Installation
From NPM:
npm install resize-observer-polyfill --save-dev
~~From Bower:~~ (will be removed with the next major release)
bower install resize-observer-polyfill --save-dev
Browser Support
Polyfill has been tested in the following browsers:
NOTE: Internet Explorer 8 and its earlier versions are not supported.
Usage Example
It's recommended to use this library in the form of a ponyfill, which doesn't inflict modifications of the global object.
import ResizeObserver from 'resize-observer-polyfill';
const ro = new ResizeObserver((entries, observer) => {
for (const entry of entries) {
const {left, top, width, height} = entry.contentRect;
console.log('Element:', entry.target);
console.log(`Element's size: ${ width }px x ${ height }px`);
console.log(`Element's paddings: ${ top }px ; ${ left }px`);
}
});
ro.observe(document.body);
Package's main file is a ES5 UMD bundle that will be swapped with the ES6 modules version for those bundlers that are aware of the module field, e.g. for Rollup or webpack 2+.
Note: global version of the polyfill (dist/ResizeObserver.global
) is deprecated and will be removed in the next major release.
Observation Strategy
As mentioned above, this implementation primarily (but not solely) relies on Mutation Observer with a fallback to Mutation Events for IE 9 and IE 10.
Speaking of Mutation Events as a fallback approach: they might not be as ugly as they are being rendered, particularly when their calls are batched, throttled and there is no need to analyze changes. Given that, they won't interrupt browser's reflow/repaint cycles (same for MutationObserver) and may even outperform Internet Explorer's implementation of MO causing little to no performance degradation. In contemporary browsers (Chrome, Firefox, etc.) Mutation Observer slows down the suite that includes 200 iterations of adding/removing elements, changing attributes and modifying text data by less than 1%. Internet Explorer gives different results with MO slowing down the same suite by 2-3% while Mutation Events show the difference of ~0.6%.
As for the reasons why other approaches, namely the iframe/object and scroll
strategies, were ruled out:
- They require the observed element to be non-statically positioned.
- You can't apply them directly to quite a number of elements:
<img>
,<input>
,<textarea>
,<canvas>
,<tr>
,<tbody>
,<thead>
,<table>
, etc. For most of them you would need to keep an extra<div>
wrapper and almost all instances of the SVGGraphicsElement will be out of scope. - The ResizeObserver spec requires to deliver notifications when a non-empty visible element becomes hidden, i.e. when either this element directly or one of its parent nodes receive the
display: none
state. Same goes for when it's being removed from or added to the DOM. It's not possible to handle these cases merely by using former approaches, so you'd still need to either subscribe for DOM mutations or to continuously check the element's state.
And though every approach has its own limitations, I reckon that it'd be too much of a trade-off to have those constraints when building a polyfill.
Limitations
- Notifications are delivered ~20ms after actual changes happen.
- Changes caused by dynamic pseudo-classes, e.g.
:hover
and:focus
, are not tracked. As a workaround you could add a short transition which would trigger thetransitionend
event when an element receives one of the former classes (example). - Delayed transitions will receive only one notification with the latest dimensions of an element.
Building and Testing
To build polyfill. Creates UMD bundle in the dist
folder:
npm run build
To run a code style test:
npm run test:lint
Running unit tests:
npm run test:spec
To test in a browser that is not present in karma's config file:
npm run test:spec:custom
Testing against a native implementation:
npm run test:spec:native
NOTE: after you invoke spec:native
and spec:custom
commands head to the http://localhost:9876/debug.html
page.