uni-app x DOM API 实战:UniResizeObserver 元素尺寸监听完全指南
2026/9/19 15:56:58 网站建设 项目流程

uni-app x DOM API 实战:UniResizeObserver 元素尺寸监听完全指南

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

UniResizeObserver 是 uni-app x 提供的 DOM API,用于持续监视 UniElement 元素的大小变化,可在 view、text、image、scroll-view 等任意组件元素上建立"观察—回调"机制。本文以 官方文档 为主体,结合仓库中的完整示例页与真实组件源码,讲解其构造函数、observe / unobserve / disconnect 三个核心方法、回调数据结构、跨端兼容性及生命周期管理实践,读完即可在 UVUE 页面中落地"响应式尺寸"能力。

UniResizeObserver 是什么:UVUE 版的 ResizeObserver

在 Web 开发中,ResizeObserver用于监听 DOM 元素盒模型尺寸变化,是构建自适应布局、按容器大小调整子组件样式的标准工具。uni-app x 在 UVUE 渲染引擎中提供了同名能力的跨端封装——UniResizeObserver,其职责在 官方文档 中定义得非常明确:

用于监视 UniElement 元素的大小变化。它可以观察一个或多个目标。

uni.createSelectorQuerygetBoundingClientRect等"一次性取样"的 API 不同,UniResizeObserver 是持续监听模型:只要被观察元素的实际尺寸(content box / border box)发生变化,回调函数就会被触发,并将变化的尺寸数据以UniResizeObserverEntry数组的形式传给开发者。这一特性使其非常适合:

  • 容器尺寸自适应场景:根据父容器宽高动态计算子组件的 loading 大小、字体尺寸、圆角半径;
  • 响应式组件内部实现:当宿主元素被用户拉伸、被数据驱动改变宽高时,同步更新内部样式;
  • 布局变化监控:监听 image 加载后、text 换行后、scroll-view 宽度变化等引起的外层元素尺寸联动。

从仓库源码看,UniResizeObserver 与 Web 原生ResizeObserver在设计上一一对应。在 uni-loading 组件的 useLoadingStyle.uts 中可以看到官方组件通过条件编译在两端选择同一套监听逻辑:

// #ifdef WEB export type _Element = HTMLElement type _ResizeObserver = ResizeObserver // #endif // #ifdef APP export type _Element = UniElement type _ResizeObserver = UniResizeObserver // #endif

也就是说:Web 端使用浏览器原生ResizeObserver,App 端(UVUE)使用UniResizeObserver,二者 API 形状保持一致,便于一套代码多端复用。

兼容性矩阵:各平台支持版本

UniResizeObserver 类本身

官方文档给出的UniResizeObserver整体兼容性如下:

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | 4.16 | x | 4.13 | 4.18 | 4.61 |

其中微信小程序列标记为x,表示微信小程序端不支持该 API(小程序端对应的能力需另寻方案,如uni.createSelectorQueryboundingClientRect轮询或平台自身观测能力)。

observe / unobserve 参数(target: UniElement)的兼容性

observe()unobserve()方法接受的target参数,其兼容性表与类本身略有差异,官方文档单独列出:

| 名称 | 类型 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :- | :- | | target | UniElement | 是 | Web: 4.0; 微信小程序: 4.41; Android: 4.0; iOS: 4.11; HarmonyOS: 4.61 | 被监视 / 取消监视的 UniElement |

可以看到,observe/unobservetarget参数在微信小程序 4.41 起也可用(参数层面),但类本身在小程序端标记为x,实际使用请以具体 HBuilderX 版本的端侧表现为准,必要时做条件编译降级处理。

仓库 发布记录 也从侧面印证了该 API 的演进轨迹:

  • App-Android 平台新增 DOM API UniResizeObserver 监视 UniElement 元素的大小变化;
  • Web 平台、App-iOS 平台补齐 API UniResizeObserver 监视 UniElement 元素的大小变化;
  • App-iOS 平台修复 4.18 版本引发的 UniResizeObserver 监视元素大小变化可能导致的内存泄漏。

构造函数与回调签名

官方文档在构造函数一节给出了两种重载签名(文档中该节重复出现,实为两种可用的回调形态):

签名一:仅回调

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | callback |(entries: Array<UniResizeObserverEntry>) => void| 是 | 每当监视的元素调整大小时,回调该函数 |

签名二:回调 + observer 引用

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | callback |(entries: Array<UniResizeObserverEntry>, observer: [UniResizeObserver](https://link.gitcode.com/i/16bcead5987846713115d1720056ab0c)) => void| 是 | 每当监视的元素调整大小时,回调该函数 |

第二种签名在回调参数中额外暴露了 observer 实例本身,可在回调内部直接引用当前观察器(例如在回调中根据尺寸阈值动态决定是否unobserve自己)。

回调参数entries是一个Array<UniResizeObserverEntry>一次回调可能携带多个目标元素的尺寸数据(当一个 observer 同时观察多个元素、且它们在同一帧内都发生尺寸变化时),开发者在回调中应遍历entries并依据entry.target区分具体是哪个元素发生了变化。

核心方法:observe / unobserve / disconnect

UniResizeObserver 的方法集中在 文档的 @uniresizeobserver-methods 小节:

observe(target: UniElement): void

开始监视指定 UniElement 的大小变化。同一个 observer 可以多次调用observe观察多个目标元素,满足文档所述"观察一个或多个"的能力。

| 名称 | 类型 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :- | :- | | target | UniElement | 是 | Web: 4.0; 微信小程序: 4.41; Android: 4.0; iOS: 4.11; HarmonyOS: 4.61 | 被监视的 UniElement |

unobserve(target: UniElement): void

结束对指定 UniElement 的监视。参数语义与observe完全一致(取消监视的 UniElement),仅对之前被observe过的目标生效,不会影响其他仍在观察中的目标。

disconnect(): void

取消所有对 UniElement 目标的监视,一次性释放整个 observer 与所有目标的关联。通常在页面销毁(onUnmounted/onBackPress)时调用,是避免内存泄漏的关键操作。

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | 4.16 | x | 4.13 | 4.18 | 4.61 |

回调数据结构:UniResizeObserverEntry

官方文档本身未单独为UniResizeObserverEntry建立页面,但其结构可以从仓库示例页 uni-resize-observer.uvue 中完整还原。示例页中将其解析为如下字段(与 Web 标准 ResizeObserverEntry 一致):

type ContentRectType = { x: number, y: number, width: number, height: number, } type BoxSizeType = { blockSize: number, inlineSize: number, } type ResizeInfoType = { contentRect: ContentRectType, // entry.contentRect borderBoxSize: BoxSizeType, // entry.borderBoxSize[0] contentBoxSize: BoxSizeType, // entry.contentBoxSize[0] devicePixelContentBoxSize: BoxSizeType,// entry.devicePixelContentBoxSize[0] }

示例页中的解析辅助函数(uni-resize-observer.uvue)展示了各字段的实际取值方式:

function analysisResizeObserverEntry(entry : UniResizeObserverEntry) : string { const contentBoxSize = entry.contentBoxSize[0] const borderBoxSize = entry.borderBoxSize[0] const devicePixelContentBoxSize = entry.devicePixelContentBoxSize[0] return "borderBoxSize: \n{blockSize:" + borderBoxSize.blockSize + ", inlineSize:" + borderBoxSize.inlineSize + "}\n" + "contentBoxSize: \n{blockSize:" + contentBoxSize.blockSize + ", inlineSize:" + contentBoxSize.inlineSize + "}\n" + "devicePixelContentBoxSize: \n{blockSize:" + devicePixelContentBoxSize.blockSize + ", inlineSize:" + devicePixelContentBoxSize.inlineSize + "}\n" + "contentRect: \n{x:" + entry.contentRect.x + ", y:" + entry.contentRect.y + ", width:" + entry.contentRect.width + ", height:" + entry.contentRect.height + "}" }

各字段含义整理如下:

| 字段 | 类型 | 含义 | | :- | :- | :- | |target| UniElement | 本次回调对应的被观察元素,用于多目标区分 | |contentRect| 含 x / y / width / height 的对象 | 元素 content box 相对视口的矩形信息 | |borderBoxSize|Array<{ blockSize, inlineSize }>| 含 border、padding 的边框盒尺寸(CSS 逻辑属性:blockSize 为高、inlineSize 为宽) | |contentBoxSize|Array<{ blockSize, inlineSize }>| 内容盒尺寸,不含 border、padding | |devicePixelContentBoxSize|Array<{ blockSize, inlineSize }>| 以设备像素(物理像素)为单位的内容盒尺寸,可用于高 DPR 下的精确适配 |

注意:borderBoxSize/contentBoxSize/devicePixelContentBoxSize均为数组类型,按 Web 标准语义,在单列书写模式下取[0]即可(示例代码正是这么做的)。

实战示例:监听多元素尺寸变化

仓库 src/pages/API/uni-resize-observer/uni-resize-observer.uvue 是一个完整的可运行示例,覆盖了 view 嵌套、text、image、scroll-view 四类组件的尺寸监听,并包含"停止/恢复监听""隐藏/显示元素"等交互。其核心流程如下。

1. 创建观察器并注册回调

onReady(此时元素已完成构建,可安全获取)中创建UniResizeObserver

let resizeObserver: UniResizeObserver | null = null onReady(() => { if (resizeObserver == null) { resizeObserver = new UniResizeObserver((entries : Array<UniResizeObserverEntry>) => { entries.forEach(entry => { if (entry.target == outBoxElement) { outBoxSizeInfo.value = analysisResizeObserverEntry(entry) } else if (entry.target == innerBoxElement) { innerBoxSizeInfo.value = analysisResizeObserverEntry(entry) } // ... text / image / scroll-view 同理 }) }) } })

回调中通过entry.target与预先获取的UniElement引用做相等比较,将不同元素的尺寸变化分流到对应的展示变量。

2. 获取 UniElement 并开始观察

通过uni.getElementById()获取元素对象(前提是模板中为组件设置了id),然后逐个observe

outBoxElement = uni.getElementById("outBox") if (outBoxElement != null) { resizeObserver!.observe(outBoxElement!) } innerBoxElement = uni.getElementById("innerBox") if (innerBoxElement != null) { resizeObserver!.observe(innerBoxElement!) } // 对 text、image、scroll-view 元素重复同样的 observe 调用

一个 observer 观察多个目标后,任一方块被点击改变尺寸,回调都会触发;示例中点击蓝色/红色方块会通过style.setProperty修改元素宽高:

function innerBoxClick() { if (innerBoxElement != null) { innerBoxElement!.style.setProperty("width", innerBoxElement!.offsetWidth + offset.value + 'px') innerBoxElement!.style.setProperty("height", innerBoxElement!.offsetWidth + offset.value + 'px') } }

改变字体大小(text)、图片宽高(image)、scroll-view 宽度等操作同样会引起尺寸变化并被回调捕获,验证了该 API 对常规组件元素"大小变化"的普适监听能力。

3. 停止 / 恢复监听与页面退出清理

function cancelListen() { resizeObserver!.unobserve(outBoxElement!) resizeObserver!.unobserve(innerBoxElement!) } function goOnListen() { resizeObserver!.observe(outBoxElement!) resizeObserver!.observe(innerBoxElement!) } onBackPress(() : boolean => { if (resizeObserver != null) { resizeObserver!.disconnect() } return false })
  • unobserve只针对单个目标,可以精确暂停某元素的监听;
  • 页面退出(onBackPress)时调用disconnect()释放全部观察关系,避免观察器持有元素引用造成内存泄漏——这一点与发布记录中"iOS 4.18 修复 UniResizeObserver 内存泄漏"的说明相呼应,属于官方明确关注的实践要点。

工程实践:在组件库中正确使用 UniResizeObserver

仓库中 uni-loading 组件的 useLoadingStyle.uts 提供了组件库层面的最佳实践范本——利用尺寸监听实现"loading 指示器尺寸跟随宿主元素"的自适应效果:

export function useLoadingStyle(targetElement : Ref<_Element | null>, bold : Ref<boolean>) { const loadingSize = ref('16px') const loadingBorderWidth = ref('1px') const loadingBorderRadius = ref('8px') let observer : _ResizeObserver | null = null const calculateLoadingWidth = (element : _Element, bold : boolean) => { const { width, height } = element.getBoundingClientRect() const coefficient = bold ? 2 : 1 const minSide = Math.min(width, height) loadingSize.value = `${minSide}px` loadingBorderWidth.value = `${(minSide / 16) * coefficient}px` loadingBorderRadius.value = `${minSide / 2}px` } const setupObserver = (cb : (el : _Element) => void) => { const el = targetElement.value as _Element if (!el) return // #ifdef WEB observer = new ResizeObserver((entries) => { cb(el) }) // #endif // #ifdef VUE3-VAPOR observer = new UniResizeObserver((entries) => { cb(el) }) // #endif observer!.observe(el) } onMounted(() => { setupObserver((el) => { calculateLoadingWidth(el, bold.value) }) // ... }) onUnmounted(() => { if (observer) { observer.disconnect() } }) }

这段源码展示了三条可复用的规范:

  1. 挂载时创建、卸载时释放onMountedsetupObserverobserveonUnmounteddisconnect(),与组件生命周期严格绑定;
  2. 空值防御targetElement.value为 null 时直接返回,避免对未挂载元素观察;
  3. 多端共存:通过#ifdef WEB#ifdef VUE3-VAPOR条件编译,同一套组合式函数在 Web 端用原生ResizeObserver、在 App 端用UniResizeObserver,业务代码零改动。

与 Web ResizeObserver 的差异与注意事项

基于官方文档、示例页与源码实现,使用 UniResizeObserver 时应注意以下几点:

  1. 目标必须是 UniElementobserve/unobserve的参数类型是 UniElement(所有组件 DOM 元素对象的基类),需通过uni.getElementById()或模板ref获取,不能直接传入组件实例或字符串 id。UniElement 的offsetWidthoffsetHeightstyle(CSSStyleDeclaration)等属性常与观察器配合使用(见上文示例)。
  2. 微信小程序端类本身不支持:兼容性表标记为x,跨端项目需按平台裁剪或提供降级方案。
  3. 务必成对释放unobserve(target)精确释放单目标,disconnect()全量释放;页面/组件销毁时若不清理,可能引发内存泄漏(官方曾在 iOS 4.18 修复过相关问题)。
  4. 回调批量到达:同一帧内多个被观察元素同时变化时,回调会收到包含多个entry的数组,务必用entry.target做分流,不要假设一次回调只对应一个元素。
  5. 在 onReady 后获取元素:与 UniElement 文档 中"安卓平台元素渲染时才会构建 View"的提醒一致,元素刚创建时获取对象可能为 null,示例页统一在onReady中获取元素并开始观察。

小结

UniResizeObserver 是 uni-app x DOM API 体系中实现"持续尺寸感知"的关键能力:一个观察器可同时监视多个 UniElement 目标,通过observe开始监听、unobserve精确暂停、disconnect全量释放,回调携带contentRectborderBoxSizecontentBoxSizedevicePixelContentBoxSize等完整尺寸数据。无论是自研自适应组件,还是阅读官方 uni-loading 等组件的实现,掌握该 API 都能让跨端页面在尺寸响应上真正做到"一套代码、多端一致"。更多 DOM API(如 UniElement、DOMRect、CSSStyleDeclaration)可继续查阅 docs/api/dom 目录 与示例页 uni-resize-observer.uvue。

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询