scroll
scroll
支持任意子组件的滚动列表容器。列表的滚动方向由具体的布局方式来指定:使用流式布局或者 column 方向的 flex 布局时元素沿垂直方向布局,列表可以垂直滚动;而使用 row 方向的 flex 布局时元素沿水平方向布局,列表可以水平滚动。scroll 组件不支持双向滚动(即水平和垂直方向同时可滚动)。
scroll 组件默认是使用流式布局的块级元素。
scroll 组件可以使用手势交互来滚动,垂直的 scroll 组件还支持编码器(手表的旋转表冠,模拟器上使用鼠标滚轮)滚动。
提示
本文档的可交互示例中的 scroll 不支持鼠标滚轮,请使用模拟器或者真实设备来体验。
属性
scroll
scroll 属性值是一个对象,包含以下字段:scrollX、scrollY 和 scrollState。scrollX 和 scrollY 属性分别表示水平和垂直方向的滚动位置,单位为像素;scrollState 属性表示滚动状态,其值为 、 或 ,具体含义如下表所示。通过 on 指令可以监听 scroll 属性的变化,任何由用户操作和 API 操作引起的内容位置变化都是触发监听。
scrollState 值 | 效果说明 |
|---|---|
| 已经停止滑动 | |
| 正在通过用户的手势滑动 | |
用户已松手,由 scrollTo 等方法调用或惯性等导致的滑动 |
相关信息
scroll 子元素所在的区域称作“内容”(content)区域,而列表组件实际显示出来的部分成为“视图”(view)区域。元素在内容区域布局,其尺寸可能超出视图区域,通过滚动可以改变内容的显示位置。
滚动位置的范围通常在内容区域内,即水平列表的 scrollX 在 范围内,而垂直列表的 scrollY 在 范围内。但当列表滚动到内容的头部之前时,scrollX 或 scrollY 会小于 ;同样,当滚动到内容尾部之后,scrollX 或 scrollY 的值则会大于 contentWidth 或 contentHeight。
注意
scroll 事件在滚动过程中的每一帧都会触发,在 JavaScript 代码中监听此事件可能产生明显的掉帧,因此要尽量避免使用。
scrollTop
垂直方向的滚动位置,即 scroll 组件的内容顶部到视口顶部的距离,单位为像素。可通过此属性设置滚动位置,也可以通过此属性监听滚动位置的变化。
与 scroll 属性不同,监听 scrollTop 属性本身无法区分是用户的手势滚动还是 API 调用或惯性产生的滚动。
scrollLeft
垂直方向的滚动位置,即 scroll 组件的内容左边到视口左边的距离,单位为像素。可通过此属性设置滚动位置,也可以通过此属性监听滚动位置的变化。
与 scroll 属性不同,监听 scrollLeft 属性本身无法区分是用户的手势滚动还是 API 调用或惯性产生的滚动。
scrollWidth
scroll 组件内容区域的宽度。垂直布局下的 scroll 宽度等于视图宽度,而水平布局的 scroll 宽度为所有元素宽度之和。可通过此监听内容宽度的变化。
scrollHeight
scroll 组件内容区域的高度。垂直布局下的 scroll 高度等于视图高度,而水平布局的 scroll 高度为所有元素高度之和。可通过此监听内容高度的变化。
damping
设置列表滚动动画的阻尼系数,有效取值范围为 (不支持的值会自动修改为上下限),默认值为 。更大的阻尼系数会使动画停顿得更快,默认的阻尼系数值可以产生距离比较长、持续时间也比较久的惯性效果。
<div>
<span>damping: {{damping}}</span>
<button on:click="increase">+</button>
<button on:click="decrease">-</button>
<scroll :damping="damping">
<p for="x in 50" class="item">
Item {{ x + 1 }}
</p>
</scroll>
</div>
export default {
data: {
damping: 1
},
increase() {
this.damping += 1
if (this.damping > 20)
this.damping = 1
},
decrease() {
this.damping -= 1
if (this.damping < 1)
this.damping = 19.5
}
}
span {
color: #404040;
}
scroll {
display: flex;
flex-direction: column;
background-color: #f0f0f0;
height: 300px;
width: 360px;
}
.item {
color: #fafafa;
background-color: #bdbdbd;
text-align: center;
padding: 20px 5px;
margin: 10px;
border-radius: 16px;
}
button {
color: #fafafa;
background-color: #adadad;
border-radius: 12px;
margin-left: 16px;
margin-bottom: 16px;
width: 1.2rem;
}
提示
阻尼系数应当设置成常量而不要修改,修改阻尼系数不会影响回弹时的动画。
snapshot
开启 snapshot 属性时,列表中的子组件会开启快照模式。相关演示可参考原生组件的 quiescent 属性。
开启快照可能提升复杂界面的帧率。例如列表项目中存在大量的文本且包含非透明的背景时,快照模式可以将大量的绘制操作缓存并合并成少量的快照。Glyphix 框架会在重复的绘制中缓存这些快照,以进一步提升性能。
但 snapshot 属性不提供对子组件使用快照的保证,当系统的内存不足,或者没有必要使用快照时可能忽略此属性。
deformation
设置列表的形变效果,通过形变效果可以实现鱼眼等外观。可以通过名称(字符串)指定一种内置的形变效果,也可以通过 JavaScript 函数来定义形变效果。
| 值 | 效果说明 |
|---|---|
'none' | 无形变效果(默认值) |
'fisheye' | 内置的鱼眼效果 |
| function | 通过 JavaScript 函数指定形变效果 |
形变效果应该是常量而不要修改。
当列表设置为鱼眼形变效果时建议将 scrollSnap 属性设置为 'center',以得到最合理的效果。
下图演示了鱼眼形变效果,通过“center”开关可以调节是否居中对齐。
<div>
<p>center <switch ::value="center" /></p>
<scroll deformation="fisheye" :scroll-snap="center ? 'center' : null">
<p for="x in 15">
Item {{ x + 1 }}
</p>
</scroll>
</div>
div {
color: #404040;
display: flex;
flex-direction: column;
}
scroll {
display: flex;
flex-direction: column;
background-color: #f0f0f0;
flex: 1;
}
scroll > p {
color: #fafafa;
background-color: #bdbdbd;
text-align: center;
padding: 40px 10px;
margin: 5px;
border-radius: 50%;
}
export default {
data: {
center: true
}
}
提示
形变效果一般会用到快照,所以在设置有 deformation 属性时无需重复设置 snapshot。
scrollSnap
设置列表项目的对齐和吸附方式。例如可以让元素居中对齐,或者在元素边界上吸附。
| 值 | 描述 |
|---|---|
'none' | 元素无吸对齐和附效果,即子元素可按照滚动惯性停止在任何位置。 |
'start' | 滚动停止时元素起始位置对齐到视口起始位置。此模式目前不支持。 |
'center' | 滚动停止是元素的中心位置会对齐到视口中心。 |
'edge' | 滚动停止时,元素的起始或结束位置就近对齐到视口起始或结束位置。但是如果滚动不会跨越元素边界,那么不会引起吸附。 |
scrollSnap 属性不会调整元素尺寸,但是可以利用布局等机制来实现等尺寸项目的列表。
注意
该属性应该在组件初始化时设置并且不能改变,否则可能出现交互错误。
index
当前显示的子组件索引,设置 index 属性时,组件将通过动画滚动到指定的子组件。可以通过 on 指令监听位置变化,子组件索引变化时可以通过 index 属性监听到。
index 的值会自动进行限制以保证指向有效的元素。使用 index 时必须保证 scroll 组件的所有元素都是静态的(即 CSS 的 position 属性为默认的 static),否则会出现错误。
finalChanged
设置是否只在滚动停止时触发 index 变化的事件。默认情况下(即 finalChanged 为 false),只要滚动手势或其他原因导致 scroll 组件的 index 属性变化时,都会触发其监听事件。但是这样做容易导致动画掉帧,或是过于频繁、不必要的事件触发。当设置 finalChanged 时,只有当滚动停止时才会触发 index 变化的事件。
提示
在通过监听 index 属性实现点指示器等效果时,建议将 finalChanged 设置为 true,这可以避免滑动过程因事件触发渲染更新导致的掉帧。
以下示例展示了 finalChanged 的效果。你可以尝试切换 "final-changed" 复选框,然后滑动列表,观察 index 的变化频率和时机。
<div>
<p>
<checkbox id="checkbox" ::checked="finalChanged" />
<label target="checkbox">final-changed</label>
index: {{index}}
</p>
<scroll :final-changed="finalChanged" ::index="index">
<p for="x in 50">
Item {{ x + 1 }}
</p>
</scroll>
</div>
div {
color: #404040;
display: flex;
flex-direction: column;
}
scroll {
display: flex;
flex-direction: column;
flex: 1;
}
scroll > p {
background-color: #f0f0f0;
border-radius: 12px;
text-align: center;
margin: 8px;
padding: 20px;
}
export default {
data: {
index: 0,
finalChanged: true
}
}
bounces
设置通过手势将 scroll 滚动到边界之后是否触发回弹。该属性的初始值为 edge,即允许起始位置和结束位置的回弹。
| 值 | 描述 |
|---|---|
'none' | 禁用所有边界回弹。 |
'start' | 只允许拖拽到内容起始位置后的回弹。 |
'end' | 只允许拖拽到内容结束位置后的回弹。 |
'edge' | 允许拖拽到内容起始或结束位置后的回弹。 |
下面的示例展示了各个 bounces 值的作用,你可以尝试将每一个项目左右滑动超过边界,并观察对应的交互行为。
<scroll class="column-box">
<scroll for="item in items" class="row-box"
:bounces="item" scroll-snap="edge">
<p class="item-body">bounces: {{item}}</p>
<p class="slide-button">×</p>
</scroll>
</scroll>
export default {
data: {
items: ['none', 'start', 'end', 'edge']
}
}
.column-box {
display: flex;
flex-direction: column;
}
.row-box {
display: flex;
flex-direction: row;
}
.row-box > p {
border-radius: 12px;
text-align: center;
margin: 8px;
padding: 16px;
}
.item-body {
background-color: #f0f0f0;
width: 100%;
}
.slide-button {
width: 30%;
color: #ffffff;
background-color: #f04040;
}
注
目前 bounces 属性仅影响手势操作的回弹,但忽略了快速的惯性动画回弹。上面的示例使用了一种技巧来避免非预期行为:
.row-box使用边沿吸附策略(snap-type="edge"),以避免带回弹的手势动画。.row-box的每个元素都不超过100%宽度,确保边沿吸附策略不会发生内部边界回弹。
这种技巧可以用于侧滑删除菜单等界面。
bounces 属性也会起到和 weakGesture 类似的作用。具体来说,当越过禁止回弹的边沿后会自动允许滚动手势事件冒泡传递。因此,无需同时设置 bounces 和 weakGesture 属性。
提示
bounces 和 weakGesture 的滚动手势冒泡行为是“相反”的,例如 end 模式回弹策略允许用户滚动过列表结束位置后的回弹,而这种策略会允许起始位置的滚动手势冒泡。这对应值为 'start' 的 weakGesture 属性效果。
weakGesture
设置 scroll 组件在哪些情况下会对滚动手势进行冒泡。默认情况下 scroll 对它响应的手势阻止冒泡,因此它的父级元素无法接收到使 scroll 滚动的手势。weakGesture 允许在拖拽到内容边界位置时对手势事件启用冒泡,从而使父级元素能够接收这些手势。
| 值 | 描述 |
|---|---|
'none' | 不对响应的手势事件进行冒泡。 |
'start' | 拖拽到内容起始位置后对响应的手势事件冒泡。 |
'end' | 拖拽到内容结束位置后对响应的手势事件冒泡。 |
'edge' | 拖拽到内容起始或结束位置后对响应的手势事件冒泡。 |
如果页面的底层元素是一个水平的 scroll 组件,但是希望右滑手势能让页面返回,那么可以这样配置:
<scroll weak-gesture="start"> ... </scroll>
当用户滑动到 scroll 组件的头部之后继续右滑即可退出页面。
注意
该属性应该在组件初始化时设置并且不能改变,否则可能出现交互错误。
scrollbar
标记 scroll 组件是否要显示滚动条(默认不显示),仅支持垂直布局的 scroll 组件。scrollbar 属性必须是一个常量,不能用响应式属性修改,例如:
<scroll scrollbar>
...
</scroll>
将会创建一个带有滚动条的 scroll 组件。滚动条的效果请参考 setIndex 方法的示例。
滚动条的样式由系统决定,例如在圆形屏幕上可能显示为弧形,而矩形屏幕上显示为直条状。
scrolled
通过 scrolled 属性监听列表是否处于滚动状态。事件触发的属性值为 true 表示列表正在滚动,否则意味着列表已经停止滚动。
用户触摸产生的滚动操作和通过 scroll 属性来滚动都会触发 scrolled 事件。当列表从滚动状态停止时,scrolled 事件的参数值为 false。
setIndex
将视口移动到由索引所指定的子组件。如果本次移动会越过视口边界,视口位置将停留在第一个或最后一个组件处。options 参数属性的作用为:
index:待移动的目标子组件的索引, 表示第一个子组件。behavior:为'smooth'时使用动画过渡,为'instant'(默认值)时立即移动到指定的子组件位置。
调用 setIndex() 时必须保证 scroll 组件的所有元素都是静态的,否则会出现错误。
<div class="window">
<scroll id="scroll"
:scroll-snap="center ? 'center' : null"
scrollbar>
<p for="x in 50" class="item">Item {{ x }}</p>
</scroll>
<div class="controls">
<button on:click="setIndex('smooth')">smooth</button>
<button on:click="setIndex('instant')">instant</button>
center <switch ::value="center" />
</div>
</div>
import prompt from '@system.prompt'
export default {
data: { center: false },
setIndex(behavior) {
let el = this.$element('scroll')
let index = parseInt(Math.random() * 50)
prompt.showToast({message: `${behavior}ly set index to ${index}`})
el.setIndex({ index: index, behavior: behavior })
}
}
.window {
display: flex;
flex-direction: column;
}
scroll {
display: flex;
flex-direction: column;
background-color: #f0f0f0;
flex: 1;
}
.item {
color: #fafafa;
background-color: #bdbdbd;
text-align: center;
padding: 20px 5px;
border-radius: 16px;
margin: 8px;
}
.controls {
display: flex;
align-items: center;
color: #404040;
}
button {
color: #fafafa;
background-color: #adadad;
border-radius: 12px;
padding: 4px 10px;
margin-left: 16px;
margin-bottom: 16px;
flex: 1;
margin: 8px;
padding: 8px;
text-align: center;
}
scrollTo
将内容滚动到指定的位置。options 参数属性的作用为:
left:指定内容沿 y 轴滚动的位置,忽略left或者 scroll 组件具有垂直布局时不会进行 y 轴上的滚动。top:指定内容沿 x 轴滚动的位置,忽略top或者 scroll 组件具有水平布局时不会进行 x 轴上的滚动。behavior:指定滚动的过渡效果,'instant'(默认值)表示直接跳转到目标位置并没有过渡效果,而'smooth'会平滑滚动并产生过渡效果。
scrollTo 方法会忽略元素的吸附效果。
scrollBy
将内容滚动一段距离。与 scrollTo() 不同,scrollBy() 是相对于当前的内容位置进行滚动。options 参数属性的作用为:
left:指定内容沿 y 轴滚动的距离,忽略left或者 scroll 组件具有垂直布局时不会进行 y 轴上的滚动。top:指定内容沿 x 轴滚动的距离,忽略top或者 scroll 组件具有水平布局时不会进行 x 轴上的滚动。behavior:指定滚动的过渡效果,'instant'(默认值)表示直接跳转到目标位置并没有过渡效果,而'smooth'会平滑滚动并产生过渡效果。
scrollBy 方法会忽略元素的吸附效果。
