API ResizeObserver的简介以及JS检测DOM尺寸变化的方法

目录
文章目录隐藏
  1. ResizeObserver 语法
  2. ResizeObserver 实际应用案例
  3. ResizeObserver 兼容性
  4. Polyfill

在过去是没有专门的 API 来检测到 DOM 元素尺寸变化的,我们大多是通过借助 window 对象上绑定 resize 事件。但是 DOM 元素的尺寸变化,有时候窗体的尺寸没有变化也会触发。还有的时候窗体的尺寸变化了,但是 DOM 元素的尺寸并没有变化,这样的话在 window 对象上绑定的 resize 事件就有些浪费。所以一个全新的 API 就很空出世了,也就是今天为大家主要讲的 ResizeObserver 对象,一个专门用来观察 DOM 元素的尺寸是否发生了变化的 API,好了废话不多说,接下来看我们的主要内容。

ResizeObserver 语法

假设我们页面上有个 DOM 元素,名叫 eleMybj,则我们想要在 eleMybj 尺寸变化的时候做点什么事情,可以使用下面的 JavaScript 代码:

var ro = new ResizeObserver( entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;
    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// 观察一个或多个元素
ro.observe(eleMybj);

此时我们在控制台就可以看到类似下图的结果:

ResizeObserver 语法

contentRect 指的是什么?

entry.contentRect 返回的是一个 DOMRect 对象,例如的属性包括:

{
    x: 0
    y: 0
    width: 296
    height: 100
    top: 0
    right: 296
    bottom: 100
    left: 0
}

如果我们给 DOM 元素设置个 padding:10px,则宽高都会变小,同时 left 和 top 属性值变成了 10。

{
    x: 10
    y: 10
    width: 276
    height: 100
    top: 10
    right: 286
    bottom: 110
    left: 10
}

这表明 contentRect 返回是 content box,也就是内容区域的尺寸。

我从 Google Developers 找了张 content box 示意图,参见下图中间那部分:

content box 示意图

同时也从侧面说明了,如果一个元素的 content box 的尺寸没有发生变化,那么也是不会触发 ResizeObserver 观察执行的,哪怕你改变了元素的 padding 值,或者改变了元素的 border-width 边框尺寸,都不会认为是 DOM 元素尺寸变化了。例如:

div {
    width: 200px; height:100px;
}

则上面这个 div 元素设置 padding:10px,是没有不会触发 ResizeObserver 执行的。

Firefox 中另外两个对象

Firefox 浏览器中,entry 还包括下面两个属性值,borderBoxSize 对象和 contentBoxSize 对象。

entry.borderBoxSize
entry.contentBoxSize

都返回 ResizeObserverSize 对象,该对象展开为:

{ 
    inlineSize: 271,
    blockSize: 41
}

其中 inlineSize 表示内联元素排列方向上的尺寸,等同于 CSS 逻辑属性 inline-size,在默认文档流下表示宽度;blockSize 表示块级元素排列方向上的尺寸,等同于 CSS 逻辑属性 block-size,在默认文档流下表示高度。

ResizeObserver 实际应用案例

1.原生 resize 行为的检测

例如,有了 ResizeObserver,我们就可以检测<textarea>的 resize 拉伸行为了。

比方说<textarea>尺寸拉伸的时候,我们可以让边框的颜色不断变化起来。

如下 GIF 录屏效果所示:

原生 resize 行为的检测

相关代码如下:

var objResizeObserver = new ResizeObserver(function (entries) {
    var entry = entries[0];
    var cr = entry.contentRect;
    var target = entry.target;
    
    var angle = (cr.width - 200) + (cr.height - 100);
    target.style.borderImage = 'linear-gradient('+ angle +'deg, deepskyblue, deeppink) 1';
});
// 观察文本域元素
objResizeObserver.observe(eleTextarea);

2.感知交互行为的发生

当元素里面的内容变多或变少的时候,如果没有把高度和宽度定死,则我们可以通过观察元素的尺寸是否有变化,而知道是否有交互行为发生。

例如,我们在使用 Ajax 发表评论的时候,需要把评论写入到现有的评论列表,通过观察评论容器的尺寸变化,我们就可以认为这个评论交互已经完成,然后脱离具体的业务逻辑完成其他一些需求,例如数据埋点,我们只需要观察特定容器尺寸是否变化,然后发送埋点数据即可。优点是数据埋点无侵入,无需写入到业务逻辑中,非常灵活,也利于日后维护。

3.感知元素是否显示或隐藏

当一个元素使用 display:none 进行隐藏的时候,也是会触发尺寸变化的,于是也能够被观测到。

基于尺寸的观测要比基于属性的观测要更精准。因为一个元素的隐藏可能是通过其他元素的属性变化触发的,例如其他元素添加了一个类名,这个类名正好可以影响当前元素的隐藏。

例如:

<button id="button">点击我</button>
<img id="img" src="./mm.jpg" >
button.active + img {
    display: none;
}

按钮元素添加类名.active 会导致后面的图片隐藏,此时通过 MutationObserver 观察图片属性或节点的变化是没有任何用的。

此时应该使用 ResizeObserver。

var objResizeObserver = new ResizeObserver(function () {
    if (getComputedStyle(img).display == 'none') {
        console.log('图片隐藏了');
    } else {
        console.log('图片显示了');
    }
});
// 观察图片元素
objResizeObserver.observe(img);

点击 demo 页面的按钮,就可以看到图片的显隐效果,以及对应的状态变化的描述。

MutationObserver 观察图片属性

ResizeObserver 兼容性

这个 API 游览器支持的非常迅速,我记得去年看的时候才 chrome 浏览器支持,现在 Firefox 浏览器也支持了,Safari 也确定会支持,估计不用多久就可以使用了。

ResizeObserver 兼容性

Polyfill

Polyfill 项目地址:点击这里

理论上可以兼容到 IE9 浏览器,不过还需要引入其他 Polyfill,IE11+以及其他现代浏览器直接引入项目 JS 就可以了。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » API ResizeObserver的简介以及JS检测DOM尺寸变化的方法

发表回复