你的改变,我看得见!
今天要介绍的是 ResizeObserver,它和昨天的 MutationObserver 非常相像,都是透过「观察者模式」的设计方式来监测元素,不过 ResizeObserver 监测的变动是元素的「大小」。
各位应该有使用过 window 的 resize
事件吧?只要视窗大小有更动,事件就会触发并执行 Callback,然後各位也一定跟我一样,肖想着把 resize
事件绑定在一般元素上,可想而知是不会成功的,但 ResizeObserver 的出现,终於可以实现我们的愿望了。
ResizeObserver 一样是一个建构函式,所以需要使用 new
关键字来建立实体,建立时需要传入一个 Callback Function 作为参数,该 Function 可以接到由 ResizeObserver 提供的一个阵列作为参数,该阵列中会一个或多个 ResizeObserverEntry 物件:
const observer = new ResizeObserver(function (entries) {
console.log(entries);
});
就和昨天说的一样,ResizeObserver 创建後并不会直接开始进行观察,我们需要透过 observe
来注册想要监测的元素,这样 ResizeObserver 才会在该元素发生变动时进行动作,这里有两个参数传入:
content-box
和 border-box
两种,预设为 content-box
。(其实有第三种,但使用度很低)如果对盒模型不太熟悉的朋友可以看这里了解一下
const observer = new ResizeObserver(function (entries) {
console.log(entries);
});
const div = document.querySelector("div");
observer.observe(div, {
box: "border-box",
});
这样只要受到监测的元素发生宽高的变化,ResizeObserver 就会执行我们指定的行为了。
和 MutationObserver 一样,只要使用 disconnect
这个 method 就可以注销目前所有被观察的元素,後续只要再次呼叫 observe
来注册一个被观察的元素,ResizeObserver 依然会持续运作。
const observer = new ResizeObserver(function (entries) {
console.log(entries);
});
observer.disconnect();
ResizeObserver 除了 disconnect
之外,还额外多了一个 unobserve
method,它可以让我们注销「单个」元素的观察,当某个元素已经不在需要受到监测,就可以将其做为参数,unobserve
便会把它从 ResizeObserver 的监测中移除。
const observer = new ResizeObserver(function (entries) {
console.log(entries);
});
const div = document.querySelector("div");
observer.observe(div, {
box: "border-box",
});
observer.unobserve(div);
一样的,ResizeObserver 为了优化效能问题,如果有一连串连续且即时的元素尺寸变动,那 ResizeObserver 并不会一次次触发,而是会将它们合并成一次变动,并且只会纪录最终的结果。
而如果同一时间中,有多个观测中的元素都发生了尺寸变动,那 ResizeObserver 就会有相应数量的纪录,这也就是为什麽会以阵列形式来包装 ResizeObserverEntry 物件。
const observer = new ResizeObserver(function (entries) {
entries.forEach((entry) => {
console.log(entry); // ResizeObserverEntry 物件
});
});
const element1 = document.querySelector("#element1");
const element2 = document.querySelector("#element2");
observer.observe(element1);
observer.observe(element2);
element1.style.width = "300px";
element1.style.height = "200px";
element2.style.width = "300px";
element2.style.height = "200px";
// 看似是四次变动,但 ResizeObserver 只会视为「两个元素的一次变动」
// 因此 callback 只会触发一次,且 entries 中会有两组 ResizeObserverEntry
ResizeObserverEntry 的属性虽然不多,但都较为复杂,所以下面就一一拉出来说明:
ResizeObserverEntry.contentRect
这个属性的值为一个 DOMRectReadOnly 物件,该物件会纪录很多 target
的相关资讯:
contentBox
在该元素中的X座标,通常等於 padding 宽度。contentBox
在该元素中的Y座标,通常等於 padding 宽度。contentBox
的宽度。contentBox
的高度。contentBox
的「顶边」的Y座标,通常与 y
相同。contentBox
的「底边」的Y座标,通常与 y + height
相同。contentBox
的「左侧」的X座标,通常与 x
相同。contentBox
的「右侧」的X座标,通常与 x + width
相同。ResizeObserverEntry.borderBoxSize
这个属性会是一个阵列,而阵列中会是一个或多个 borderBoxSize 物件,该物件中又会有两个属性:
blockSize: 这个属性的值会是一个数值,该数值通常代表元素的高,会说通常是因为,这取决於元素被设定的书写方向,blockSize
代表的是「垂直」於书写方向的元素边长尺寸(单位:px)。
inlineSize: 而 inlineSize
刚好相反,它代表的是「平行」於书写方向的元素边长尺寸(单位:px)。
ResizeObserverEntry.contentBoxSize
这个属性会是一个阵列,而阵列中会是一个或多个 contentBoxSize 物件,而物件中一样会有两个属性,其实跟 borderBoxSize 物件是一样的,但是两者的差别在於尺寸的计算方式,borderBoxSize 是依照 border-box
的方式计算,contentBoxSize 则是依 content-box
进行计算。
blockSize: 「垂直」於书写方向的元素边长尺寸(单位:px)。
inlineSize: 「平行」於书写方向的元素边长尺寸(单位:px)。
以上这些资讯我们都可以在 Callback 中取得,想要做任何判断或计算都是非常方便,所以大家可以根据需求去决定需要利用的资讯有哪些。
const observer = new ResizeObserver(function (entries) {
entries.forEach((entry) => {
const target = entry.target;
const borderBox = entry.borderBoxSize[0];
console.log(`${target.id} 宽度: ${borderBox.inlineSize} 高度: ${borderBox.blockSize}`);
});
});
相比 MutationObserver,ResizeObserver 的使用情境就比较多了,因为今天元素的变动会受到很多因素影响,且大部分都不是我们可以完全预测掌控的,例如视窗大小的压缩、元素内容的增加/减少、RWD 的控制的等等,这时就可以透过 ResizeObserver 来监测元素的大小,并做出相对应的动作。
<<: 30-20 之 Domain Layer - UnitOfWork
>>: [Day22] - Django-REST-Framework GenericAPIViews 和 Mixins 介绍
工程师太师了: 第12.5话 杂记: <纯靠北工程师>是个Facebook匿名社群粉专,...
JQuery DOM元素操作 透过text()、Val()来显示文本内容 范例一 <p id=...
iOS APP iOS Test-Driven Development by Tutorials f...
题干懒人包 给定一个排列好的列表,将它整理成重复项最多出现两次,比方说以下 [1,1,1,2,2,3...
中秋节就是要烤肉阿! 台式烤肉吃腻了来换换口味吧, 韩剧及韩综中常常出现韩国烤五花肉,在家就可以吃!...