ResizeObserver

无渲染尺寸监听工具组件,封装浏览器原生 ResizeObserver,监听元素盒模型尺寸变化并抛出归一化尺寸。

设计文档(新窗口打开)

使用场景

ResizeObserver 封装浏览器原生 ResizeObserver API,监听元素的盒模型尺寸变化,并以归一化、可节流/防抖的方式向外抛出尺寸信息。它不渲染任何可见 UI、不持有视觉样式,只测量并广播尺寸。

典型用途:容器级响应式布局(替代视口 media query)、虚拟列表行高测量、浮层随目标尺寸重定位、文本省略检测、自适应列宽。

与 Semi 的定位差异:Semi 的 resizeObserver 是内部实现细节——它有组件目录、被 Table / Tabs / Tooltip / TextArea / Collapsible 等十余个组件消费,但不从 semi-ui 导出、也没有文档页。本库把它作为公开基座导出(ResizeObserver 组件 + resize action + createResizeObserver),因为本库同样有十余个内部消费方,且 Svelte 生态缺少对应轮子,故一并对外提供并保留本页文档。API 以本库为准:Semi 内部版本仅有 onResize / observeParent / observerProperty / delayTick 四个 prop(其中 delayTick 在 Semi 中声明后从未被读取,属死 prop,本库不实现;节流能力由 throttle / debounce 承担)。

渲染差异:Semi 用 React.cloneElement 把 ref 挂到唯一子元素上,自身不产生 DOM。Svelte 无法向 snippet 注入 ref,故本库渲染一个无视觉样式的包裹元素(默认 div,可用 tag 改);但开启 observeChild 即可让观测目标落到 children 首个元素本身,尺寸语义与 Semi 一致(同本库 Dropdown 处理 cloneElement 的手法)。包裹元素需生成盒子,因此不使用 display: contents。

代码演示

如何引入

import { ResizeObserver } from '@chenzy-design/svelte';

基础尺寸观察

包裹目标内容,通过 slot 参数实时获取容器宽高。拖拽下方容器右下角即可调整。

拖拽右下角调整容器大小,实时显示尺寸
0 × 0 px

调整中 / 调整完成

onResizeStart 在一段连续尺寸变化的首帧触发,onResizeEnd 在静默一段时间后触发并回传最后一帧,适合「拖拽中显示实时尺寸、松手后提交一次」的场景。

拖拽调整时显示“调整中”,松手静默后提交“调整完成”
空闲
0 × 0 px

响应式切换布局

按容器宽度(而非视口宽度)在断点两侧切换布局,实现组件级响应式。

容器宽度 < 360px 时纵向堆叠,否则横向并排
紧凑(纵向)
0 px
侧栏
主内容区

多目标观测

开启 multiple 后观测包裹元素的所有直接子元素,onResize 逐个抛出,用 entry.target 区分来源。

multiple 模式:分别监听三个可独立调整大小的子卡片
A: — pxB: — pxC: — px
卡片 A
卡片 B
卡片 C

观测父容器

observeParent 观测包裹元素的父节点而非自身(对齐 Semi observeParent),用于「监听我所处容器的尺寸」而无需再包一层被观测元素。与 multiple 互斥,同时为 true 时 multiple 优先。

拖拽外层容器右下角:内部组件同时观测自身与「父容器」,此处只展示父容器尺寸
父容器:— px

只监听某一维度

observerProperty 设为 width 或 height 时(对齐 Semi observerProperty),逐目标记忆上次上报值,另一维度单独变化不触发回调,可减少无谓重算。

同时拖拽宽和高:左侧仅宽度变化才计数,右侧仅高度变化才计数
observerProperty="width"
0 × 0 px · 回调 0 次
observerProperty="height"
0 × 0 px · 回调 0 次

API 参考

ResizeObserver

属性说明类型默认值
box观测盒模型'content-box' \| 'border-box' \| 'device-pixel-content-box'content-box
children内容 slot,作用域参数 { width, height, entry }Snippet<[{ width, height, entry }]>-
class包裹元素类名string-
debounce防抖等待(ms),trailing-only。与 throttle 互斥且优先number0
disabled暂停尺寸分发(observer 仍监听,仅不向外通知)booleanfalse
fallbackToWindow原生不可用或显式开启时,降级监听 window.resize 近似重测booleanfalse
multiple观测包裹元素内所有直接子元素(而非包裹元素本身)booleanfalse
observeOnMount挂载后立即测量一次booleantrue
observeChild观测 children 首个元素而非包裹元素本身(对齐 Semi 直接观测子元素的语义);无子元素时回退观测包裹元素booleanfalse
observeParent观测包裹元素的父节点而非自身。优先级:multiple > observeChild > observeParentbooleanfalse
observerProperty仅当指定维度变化时才回调'width' \| 'height' \| 'all'all
onFirstMeasure首次测量回调(entry: CDResizeEntry) => void-
onResize尺寸变化回调(归一化 entry)(entry: CDResizeEntry) => void-
onResizeEnd连续变化静默结束后触发,回传最后一帧(entry: CDResizeEntry) => void-
onResizeStart一段连续尺寸变化的首帧触发(entry: CDResizeEntry) => void-
tag包裹元素标签,须为能生成盒子的元素stringdiv
throttle节流间隔(ms),leading + trailingnumber0

CDResizeEntry

归一化后的尺寸负载,回调与 slot 参数均使用该结构(消费方无需再调 getBoundingClientRect)。

字段说明类型
box该次测量所用盒模型ResizeBox
height高度(px)number
target发生尺寸变化的元素Element
width宽度(px)number

resize action

轻量用法,直接把监听挂到任意元素上,无需包裹容器。

import { resize } from '@chenzy-design/svelte';
<div use:resize={{ throttle: 16, onResize: (e) => console.log(e.width, e.height) }}>...</div>
参数说明类型默认值
box观测盒模型。变化时重建 observerResizeBoxcontent-box
debounce防抖等待(ms)。变化时重建 observernumber0
fallbackToWindow降级监听 window.resize。变化时重建 observerbooleanfalse
observerProperty仅当指定维度变化时才回调。变化时重建 observer'width' \| 'height' \| 'all'all
onResize尺寸变化回调。变化时原地更新,不重建(entry: CDResizeEntry) => void-
onResizeEnd连续变化静默结束后触发。变化时原地更新(entry: CDResizeEntry) => void-
onResizeStart连续变化首帧触发。变化时原地更新(entry: CDResizeEntry) => void-
throttle节流间隔(ms)。变化时重建 observernumber0

createResizeObserver

底层工厂(来自 @chenzy-design/core),供不使用组件 / action 的场景直接调用,返回 supported / observe / unobserve / disconnect。另有 getGlobalResizeObserver 提供单例 observer 池,供大列表共享一个原生实例。

无障碍

  • 本组件无可聚焦元素、无 role、无 aria 语义,不进入无障碍树;包裹元素不添加任何 aria 属性,避免污染语义树
  • 监听尺寸变化不移动焦点、不触发 scrollIntoView
  • 尺寸变化驱动的内容更新不应造成意外的视口跳动 / 回流(WCAG 2.1 §1.4.10 Reflow、§2.3.3 Animation from Interactions);节流 / 防抖即为防止「连续重排导致辅助技术读屏抖动」的关键缓解措施
  • 本组件不自动播报尺寸变化(避免噪音),如需播报由消费方自行处理