DOM – ResizeObserver
介绍
想监听一个 element 的 size changes 就可以使用 ResizeObserver 了.
在看这一篇之前, 建议先看看 DOM & BOM – IntersectionObserver, 它们的模式很像, 一起了解会比较容易.
效果
参考:
Youtube – Learn Resize Observer In 5 Minutes
场景
<body> <button class="button">resize</button> <div class="box">resize me</div> </body>
CSS Style
.box { margin-top: 3rem; width: 100px; height: 100px; background-color: pink; border: 2px solid red; padding: 1rem; }
new ResizeObserver()
const rs = new ResizeObserver((entries) => { console.log("entry", entries[0]); }); rs.observe(document.querySelector(".box")); document.querySelector(".button").addEventListener("click", () => { document.querySelector(".box").style.width = "400px"; });
调用, observe, unobserve 方式和 IntersectionObserver 是一样的.
new 实例 > observe > 当观察的元素 resize 就会触发回调. 不想观察了就 unobserve。
Callback Info
绿点是常用到的, 其它的就不介绍了
borderBoxSize, 它是 array 哦, 但我不知道什么时候会超过 1 个啦.
blockSize 就是 height, inlineSize 就是 width. 这个是 Logical Properties 的写法.
ContentBoxSize, 顾名思义它就是依据 box-sizing: content-box 的计算方式 (width 不包含 padding 和 border).
contentRect: 它的 width 和 height 是扣除了 padding, border 的, 至于 rect, 它并不是 boundingClientRect 哦, 具体是什么坐标我也没去研究, 以后有需求在来补上呗.
触发时机
ResizeObserver 会在 ui render 后触发,据说是在 layout 之后 paint 之前。
window.setTimeout(() => { const h1 = document.querySelector('h1')!; h1.classList.add('showing'); const io = new ResizeObserver(() => { console.log('ResizeObserver', performance.now()); // 2, 1088.0999999940395 h1.classList.add('showed'); }); io.observe(h1); requestAnimationFrame(() => { console.log('first requestAnimationFrame', performance.now()); // 1, 1083.7999999970198 requestAnimationFrame(() => { console.log('second requestAnimationFrame', performance.now()); // 3, 1094.0999999940395 }); }); }, 1000);
第一次 requestAnimationFrame 触发在 ui render 之前
第二次 requestAnimationFrame 触发在 ui render 之后
ResizeObserver 在第一次 rAF 和第二次 rAF 中间触发。(注:ResizeObserver 和 IntersectionObserver 一样,observe 后会触发第一次)
另外一点,改了又改回去是不会触发 ResizeObserver 的
const box = document.querySelector(".box"); const ro = new ResizeObserver(() => console.log("resize")); ro.observe(box); window.setTimeout(() => { // 修改 dimension box.style.width = '100px'; box.style.height = '100px'; // 读取 dimension,这里会导致游览器提前 reflow console.log(box.offsetWidth); // 100 // 修改回去 box.style.width = 'auto'; box.style.height = 'auto'; }, 2000);
ResizeObserver 不会触发,即便中间有一个 reflow 也不会。
Uncaught ResizeObserver loop completed with undelivered notifications
有一个 container 和 change size button
<div class="container"> <button>change size</button> </div>
点击 button 后,container 会增加 100px
const button = document.querySelector('button'); /** @type {HTMLElement} */ const container = document.querySelector('.container'); button.addEventListener('click', () => { container.style.width = `${container.offsetWidth + 100}px`; });
与此同时,我们监听 container resize,每当 resize 后,我们又加 100px,一直到 1000px 才停。
const ro = new ResizeObserver(() => { if(container.offsetWidth <= 1000) { container.style.width = `${container.offsetWidth + 100}px`; } }); ro.observe(container);
执行上述代码,会得到一个游览器 error。
它的意思是说,我们在 ResizeObserver callback 里又做了 resize,从而导致了 resize callback 又一次被执行。
虽然它可以执行,效果也对 (注:可能某些情况下会出错哦),但就是会报错。
解决方法是给它一个 delay
const ro = new ResizeObserver(() => { if(container.offsetWidth <= 1000) { window.requestAnimationFrame(() => container.style.width = `${container.offsetWidth + 100}px`) ; } }); ro.observe(container);
这样就不会报错了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)