ScrollViewer 滚动容器
RenderScrollViewer 为单个子节点提供滚动能力,支持垂直、水平和双向滚动。它还会把可视区域信息同步给实现滚动视口接口的子组件。
LIVE CANVAS可运行组件示例
ON-DEMAND RUNTIME交互式示例将在进入视区时启动避免文档首屏同时初始化多个 Canvas Runtime
API 总览
主类:
RenderScrollViewer
相关 public type:
ScrollDirection
导入:
import { RenderScrollViewer, type ScrollDirection } from 'ds-ui'
何时使用
- 普通内容区、设置面板、文档侧栏需要滚动。
- 子组件是自然尺寸内容,外层只负责裁剪和滚动条。
- 子组件实现了滚动视口接口,需要接收当前可视区域。
何时不要使用
- 大表格、大树、大文本编辑器已经内置滚动和虚拟化,不应再用同方向 ScrollViewer 包一层。
- 页面根部已经由工作区管理滚动时,不要再嵌套同方向滚动容器。
- 需要复杂虚拟化时,ScrollViewer 只负责滚动,不替代数据组件自身的可视范围计算。
最小示例
import { RenderScrollViewer, RenderStackPanel, RenderText } from 'ds-ui' const list = new RenderStackPanel({ orientation: 'vertical', spacing: 6,}) list.addChild(new RenderText('第一行'))list.addChild(new RenderText('第二行')) const scroll = new RenderScrollViewer({ direction: 'vertical', child: list,})
滚动方向
vertical:垂直滚动。horizontal:水平滚动。both:双向滚动。
构造参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
direction |
'vertical' | 'horizontal' | 'both' |
'vertical' |
滚动方向。 |
child |
RenderBox |
undefined |
被滚动的唯一子节点。 |
属性和方法
| API | 类型 / 返回值 | 说明 |
|---|---|---|
child |
RenderBox | undefined |
当前唯一子节点。 |
direction |
ScrollDirection |
滚动方向。运行时修改后应触发布局或由父级重建。 |
scrollX |
number |
横向滚动偏移。赋值时会被限制到合法范围。 |
scrollY |
number |
纵向滚动偏移。赋值时会被限制到合法范围。 |
scrollBarSize |
number |
当前主题下滚动条尺寸。 |
setChild(child) |
void |
替换子节点,解除旧子节点父子关系并触发布局。 |
revealDescendant(target, margin?) |
boolean |
尽量让后代节点进入视窗。滚动位置变化时返回 true。 |
滚动到目标
revealDescendant(target, margin) 可以让某个后代节点尽量进入可视区域。
import { RenderScrollViewer, RenderStackPanel, RenderText } from 'ds-ui' const list = new RenderStackPanel({ orientation: 'vertical', spacing: 6,})list.addChild(new RenderText('第一行')) const scroll = new RenderScrollViewer({ direction: 'vertical', child: list })scroll.revealDescendant(list, 12)
业务组件在执行定位、搜索跳转、选中项跳转时,可以调用这个方法。但如果目标已经在视窗内,应优先保持当前滚动位置,避免点击后界面跳动。
布局规则
- ScrollViewer 自身尺寸由父约束决定;无界宽度默认按
300,无界高度默认按200。 - 垂直滚动时,子节点最大宽度为视窗宽度减去滚动条宽度,高度无界。
- 横向滚动时,子节点最大高度为视窗高度减去滚动条宽度,宽度无界。
- 双向滚动时,子节点在两个方向都可以自然伸展。
- 如果内容尺寸超过视窗,才绘制对应方向滚动条。
- 子节点 offset 会设置为
-scrollX/-scrollY,绘制时通过 clip 限制在视窗内。
事件行为
| 操作 | 行为 |
|---|---|
| 鼠标滚轮 | 根据方向滚动内容。滚动后返回 true 消费事件。 |
| 滚动条拖拽 | 拖拽对应方向滚动条 thumb。 |
| 内容拖拽 | 内容可滚动时,按方向和拖拽意图接管手势。 |
| 滚动到边界 | 如果当前方向内容可滚动,即使偏移未变化也会按设计消费同方向 wheel,避免滚动穿透。 |
| 指针取消 / 释放 | 清理滚动条拖拽、内容拖拽和 pointer capture。 |
视口同步
如果子组件实现滚动视口客户端接口,ScrollViewer 会在布局和滚动时同步:
{
viewWidth,
viewHeight,
scrollX,
scrollY,
}
这适合 Masonry、MarkdownViewer 等需要知道可视区域来跳过不可见内容的组件。普通子组件无需关心这个接口。
常见错误
同方向嵌套滚动
内外两个垂直 ScrollViewer 会让 wheel 归属、边界消费和虚拟化判断变复杂。页面结构应明确“谁拥有滚动”。
用 ScrollViewer 包大表格
GridView、TreeView、PlainTextEditor 等复杂组件通常自己管理滚动。外层再包 ScrollViewer 会破坏命中、滚动条和可视范围。
期望自动回到顶部
替换内容后 ScrollViewer 不会自动把滚动位置归零。业务如果需要,应显式设置 scrollX = 0、scrollY = 0。
使用建议
- 不要在一个滚动方向上嵌套多个 ScrollViewer,滚轮和虚拟化会互相干扰。
- GridView、TreeView、PlainTextEditor、MedicalRecordEditor 这类复杂组件通常应自己管理滚动。
- 普通内容容器、设置面板、文档侧栏可以使用 ScrollViewer。
- 需要大数据性能时,滚动容器只解决裁剪和滚动条,不替代数据虚拟化。