DirectSurface UIDirectSurface UI
开始使用
组件/布局原语

布局原语 / COMPONENT

ScrollViewer

RenderScrollViewer 为单个子节点提供滚动能力,支持垂直、水平和双向滚动。它还会把可视区域信息同步给实现滚动视口接口的子组件。

文档 READY示例 1
PUBLIC APIRenderScrollViewerScrollController

FUNCTION EXPLORER

可运行示例与完整源码。

这里始终保留组件的主运行入口;文档中的示例用于补充具体功能说明。

LIVE EXAMPLE SCROLL
全屏
正在启动 DirectSurface UI 运行时…

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 包大表格

GridViewTreeViewPlainTextEditor 等复杂组件通常自己管理滚动。外层再包 ScrollViewer 会破坏命中、滚动条和可视范围。

期望自动回到顶部

替换内容后 ScrollViewer 不会自动把滚动位置归零。业务如果需要,应显式设置 scrollX = 0scrollY = 0

使用建议

  • 不要在一个滚动方向上嵌套多个 ScrollViewer,滚轮和虚拟化会互相干扰。
  • GridView、TreeView、PlainTextEditor、MedicalRecordEditor 这类复杂组件通常应自己管理滚动。
  • 普通内容容器、设置面板、文档侧栏可以使用 ScrollViewer。
  • 需要大数据性能时,滚动容器只解决裁剪和滚动条,不替代数据虚拟化。

相关文档