# 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-thresholdrefresher-default-style 为'none'时生效
  • 需要在 bindrefresherrefresh 中手动将 refresher-triggered 的值设置为true,下次将 refresher-triggered 设置为false时下拉控件才会正常回弹

# 使用效果

scroll-view

# 示例代码

<!-- 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
// 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
/*  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

# 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
// 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
/*  css */
.intro {
  margin: 30px;
  text-align: center;
}

.trans {
  transition: .2s;
}
1
2
3
4
5
6
7
8
9

在线客服