# scroll-view
可以滚动的视图区域。当使用竖向滚动时,需要给scroll-view一个固定高度,通过 CSS 设置 height。
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
scroll-x | boolean | false | 否 | 允许横向滚动 |
scroll-y | boolean | false | 否 | 允许纵向滚动 |
upper-threshold | number/string | 50 | 否 | 距顶部/左边多远时,触发 scrolltoupper 事件 |
lower-threshold | number/string | 50 | 否 | 距底部/右边多远时,触发 scrolltolower 事件 |
scroll-top | number/string | 否 | 设置竖向滚动条位置 | |
scroll-left | number/string | 否 | 设置横向滚动条位置 | |
scroll-into-view | string | 否 | 值应为某子元素 id(id 不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素 | |
scroll-with-animation | boolean | false | 否 | 在设置滚动条位置时使用动画过渡 |
refresher-enabled | boolean | false | 否 | 开启自定义下拉刷新 |
refresher-threshold | number | 45 | 否 | 设置自定义下拉刷新阈值 |
refresher-default-style | string | "black" | 否 | 设置自定义下拉刷新默认样式,支持设置 black |
refresher-background | string | "#FFF" | 否 | 设置自定义下拉刷新区域背景颜色 |
refresher-triggered | boolean | false | 否 | 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发 |
bindscrolltoupper | eventhandle | 否 | 滚动到顶部/左边时触发 | |
bindscrolltolower | eventhandle | 否 | 滚动到底部/右边时触发 | |
bindscroll | eventhandle | 否 | 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY} | |
bindrefresherpulling | eventhandle | 否 | 自定义下拉刷新控件被下拉 | |
bindrefresherrefresh | eventhandle | 否 | 自定义下拉刷新被触发 | |
bindrefresherrestore | eventhandle | 否 | 自定义下拉刷新被复位 | |
bindrefresherabort | eventhandle | 否 | 自定义下拉刷新被中止 |
# Bug & Tip
scroll-into-view
的优先级高于scroll-top
- 在滚动
scroll-view
时会阻止页面回弹,所以在scroll-view
中滚动,是无法触发onPullDownRefresh
- 若要使用下拉刷新,请使用页面的滚动,而不是
scroll-view
,这样也能通过点击顶部状态栏回到页面顶部 refresher-threshold
在refresher-default-style
为'none'时生效- 需要在
bindrefresherrefresh
中手动将refresher-triggered
的值设置为true,下次将refresher-triggered
设置为false时下拉控件才会正常回弹
# 使用效果
# 示例代码
<!-- qxml -->
<view class="page-section">
<view class="page-section-title">
<text>Vertical Scroll\n纵向滚动</text>
</view>
<view class="page-section-spacing">
<scroll-view
scroll-y="true"
style="height: 300rpx;"
bindscrolltoupper="upper"
bindscrolltolower="lower"
bindscroll="scroll"
scroll-into-view="{{toView}}"
scroll-top="{{scrollTop}}"
scroll-with-animation
>
<view id="demo1" class="scroll-view-item demo-text-1"></view>
<view id="demo2" class="scroll-view-item demo-text-2"></view>
<view id="demo3" class="scroll-view-item demo-text-3"></view>
</scroll-view>
</view>
<view class="btn-wrap">
<button size="mini" bindtap="tap">next</button>
<button size="mini" bindtap="tapMoveTop">scrollToTop</button>
</view>
</view>
<view class="page-section">
<view class="page-section-title">
<text>Horizontal Scroll\n横向滚动</text>
</view>
<view class="page-section-spacing">
<scroll-view class="scroll-view_H" scroll-x="true" bindscroll="scroll" style="width: 100%">
<view id="demo4" class="scroll-view-item_H demo-text-1"></view>
<view id="demo5" class="scroll-view-item_H demo-text-2"></view>
<view id="demo6" class="scroll-view-item_H demo-text-3"></view>
</scroll-view>
</view>
</view>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// js
const order = ['demo1', 'demo2', 'demo3', 'demo1']
Page({
data: {
toView: 'demo3',
scrollTop: null
},
tap() {
for (let i = 0; i < order.length; ++i) {
if (order[i] === this.data.toView) {
this.setData({
toView: order[i + 1],
scrollTop: 0
})
break
}
}
},
tapMoveTop() {
this.setData({
scrollTop: 0,
toView: 'demo1'
})
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* css */
.page-section-spacing {
margin-top: 60rpx;
}
.scroll-view_H {
white-space: nowrap;
}
.scroll-view-item {
height: 300rpx;
}
.scroll-view-item_H {
display: inline-block;
width: 100%;
height: 300rpx;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# scroll-view 自定义下拉刷新示例
<!-- qxml -->
<qjs module="refresh">
module.exports = {
onPulling: function(evt, instance) {
var p = Math.min(evt.detail.dy / 80, 1)
console.log(p)
var view = instance.selectComponent('.refresh-container')
view.setStyle({
opacity: p,
transform: "scale(" + p + ")"
})
}
}
</qjs>
自定义交互动画:
<scroll-view
scroll-y style="width: 100%; height: 400px;"
refresher-enabled="{{true}}"
refresher-threshold="{{80}}"
refresher-default-style="none"
refresher-background="lightgreen"
bindrefresherpulling="{{refresh.onPulling}}"
>
<view slot="refresher" class="refresh-container"
style="display: block; width: 100%; height: 80px; background: blue; display: flex; align-items: center;"
>
<view class="view1" style="position: absolute; text-align: center; width: 100%;">
下拉刷新
</view>
</view>
<view qa:for="{{arr}}" style="display: flex; height: 100px;">
<image src="https://images.unsplash.com/photo-1565699894576-1710004524ba?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1832&q=80"></image>
<image src="https://images.unsplash.com/photo-1566402441483-c959946717ed?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1600&q=80"></image>
<image src="https://images.unsplash.com/photo-1566378955258-7633cb5c823e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80"></image>
<image src="https://images.unsplash.com/photo-1566404394190-cda8c6209208?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=630&q=80"></image>
<image src="https://images.unsplash.com/photo-1566490595448-be523b4d2914?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=958&q=80"></image>
</view>
</scroll-view>
默认交互动画:
<scroll-view
scroll-y style="width: 100%; height: 400px;"
refresher-enabled="{{true}}"
refresher-threshold="{{100}}"
refresher-default-style="white"
refresher-background="lightgreen"
refresher-triggered="{{triggered}}"
bindrefresherpulling="onPulling"
bindrefresherrefresh="onRefresh"
bindrefresherrestore="onRestore"
bindrefresherabort="onAbort"
>
<view qa:for="{{arr}}" style="display: flex; height: 100px;">
<image src="https://images.unsplash.com/photo-1565699894576-1710004524ba?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1832&q=80"></image>
<image src="https://images.unsplash.com/photo-1566402441483-c959946717ed?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1600&q=80"></image>
<image src="https://images.unsplash.com/photo-1566378955258-7633cb5c823e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80"></image>
<image src="https://images.unsplash.com/photo-1566404394190-cda8c6209208?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=630&q=80"></image>
<image src="https://images.unsplash.com/photo-1566490595448-be523b4d2914?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=958&q=80"></image>
</view>
</scroll-view>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// js
const app = getApp()
Page({
data: {
arr: [],
triggered: false,
},
onReady: function () {
const arr = []
for (let i = 0; i < 100; i++) arr.push(i)
this.setData({
arr
})
setTimeout(() => {
this.setData({
triggered: true,
})
}, 1000)
},
onPulling(e) {
console.log('onPulling:', e)
},
onRefresh() {
if (this._freshing) return
// 需要在refresh逻辑中手动将triggered置为true
this.setData({
triggered: true,
})
this._freshing = true
setTimeout(() => {
this.setData({
triggered: false,
})
this._freshing = false
}, 3000)
},
onRestore(e) {
console.log('onRestore:', e)
},
onAbort(e) {
console.log('onAbort', e)
},
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/* css */
.intro {
margin: 30px;
text-align: center;
}
.trans {
transition: .2s;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
←
→
在线客服