在 Uni-app 混合开发中,处理 H5 WebView 环境下富文本内容的动态高度是一个常见难题。本文聚焦于 mp-html 组件的特定场景,分析 ResizeObserver 的应用价值与潜在风险。
1. 业务背景:mp-html 渲染的遮罩层动态适配
在结果报告业务中,我们需要根据 mp-html 渲染的 Markdown 内容高度,动态决定是否展示"解锁完整结果"的遮罩。核心挑战在于:
- 富文本内容高度不固定:包含图片、表格、代码块等多种元素
- 异步资源加载:远程图片加载导致高度"跳变"
- 响应式布局:不同屏幕宽度下内容高度不同
2. 传统方案:uni.createSelectorQuery 的局限性
typescript
// 常规做法:使用 nextTick + 选择器查询
this.$nextTick(() => {
uni.createSelectorQuery()
.select('#content')
.boundingClientRect(rect => {
this.contentHeight = rect.height;
})
.exec();
});
缺点分析
| 问题 | 具体表现 | 影响 |
|---|---|---|
| 单次快照 | 仅获取查询时刻的尺寸 | 图片加载后高度变化无法感知 |
| 时机难控 | nextTick 时资源可能未加载完成 | 拿到的是占位符高度 |
| 频繁调用 | 为"实时"需定时轮询 | 性能开销大 |
核心痛点:高度跳变
富文本中的图片加载过程:
- DOM 解析 → 图片高度为 0 或占位符
- 网络请求 → 异步等待
- 图片渲染 → 页面重排,高度瞬间变化
createSelectorQuery 只能捕获第 1 步的高度,导致遮罩层定位错误。
3. ResizeObserver 方案
为什么 ResizeObserver 适合 mp-html 场景
ResizeObserver 是浏览器原生 API,专门用于监听元素尺寸变化。对于 mp-html 渲染的富文本场景,它能精准捕捉:
- 图片加载完成后的高度撑开
- 字体大小变化导致的行高调整
- 屏幕旋转引起的宽度变化
代码实现
typescript
// #ifdef H5
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const newHeight = entry.contentRect.height;
if (newHeight > 0) {
blocks.value[index].height = newHeight;
emit("ready");
}
}
});
const el = document.getElementById("block-" + index);
if (el) observer.observe(el);
// #endif
4. 优缺点深度分析
✅ 优点
| 优点 | 说明 |
|---|---|
| 主动监听 | 无需手动触发,尺寸变化自动回调 |
| 异步友好 | 图片加载完成后的高度变化精准捕捉 |
| 高性能 | 浏览器原生实现,相比 MutationObserver + 轮询更高效 |
| 精准 | 提供 contentRect.height 精确像素值 |
⚠️ 缺点
| 缺点 | 说明 | 应对方案 |
|---|---|---|
| H5 专属 | 仅支持浏览器环境,小程序/App 端不可用 | 需结合 #ifdef H5 条件编译 |
| 兼容性 | IE 浏览器不支持 | 考虑 polyfill 或降级方案 |
| 内存泄漏风险 | 组件销毁时未断开观察 | 在 onUnmounted 中调用 observer.disconnect() |
| 触发过于频繁 | 每次微小的尺寸变化都会触发 | 结合防抖/节流处理 |
注意事项
typescript
// ❌ 错误:未清理观察者
onUnmounted(() => {
// 忘记 disconnect 导致内存泄漏
});
// ✅ 正确:组件销毁时断开观察
onUnmounted(() => {
observer?.disconnect();
});
5. 适用场景判断
| 场景 | 推荐方案 |
|---|---|
| H5 环境 + mp-html 动态高度 | ✅ ResizeObserver |
| 需要兼容小程序端 | ❌ 需降级为 createSelectorQuery + 定时器 |
| 静态内容(高度不变) | ❌ 无需使用,单次查询即可 |
| 简单业务(低频变化) | 可用 createSelectorQuery + 定时轮询 |
6. 总结
在 Uni-app H5 环境下处理 mp-html 富文本的动态高度时,ResizeObserver 是目前最优雅的解决方案。它能完美解决异步图片加载导致的"高度跳变"问题,但需要注意:
- 条件编译:仅在 H5 环境下使用
- 资源清理:组件销毁时断开观察
- 降级兼容:需要考虑不支持 ResizeObserver 的旧版浏览器
通过合理使用 ResizeObserver,可以实现丝滑的 WebView 体验,避免遮罩层错位等问题。