ScrollView 滚动区域/下拉刷新

Scan me!

用于模拟原生的滚动区域,并支持下拉刷新和加载更多 1.5.0+

引入

  1. import { ScrollView, ScrollViewRefresh, ScrollViewMore } from 'mand-mobile'
  2. Vue.component(ScrollView.name, ScrollView)

使用指南

ScrollViewRefresh为组件库内置的下拉刷新组件,仅用于作为视觉展示,需在插槽refresh)中使用,下拉刷新组件也可自定义

ScrollViewMore为组件库内置的加载更多组件,仅用于作为视觉展示,需在插槽more)中使用,加载更多组件也可自定义

代码演示

基础 添加内容

请在移动设备中扫码预览
  1. <template>
  2. <div class="md-example-child md-example-child-scroll-view md-example-child-scroll-view-0">
  3. <md-scroll-view
  4. ref="scrollView"
  5. @scroll="$_onScroll"
  6. >
  7. <div
  8. v-for="i in list"
  9. class="scroll-view-item"
  10. :key="i"
  11. @click="$_onItemClick(i)"
  12. >
  13. {{i}}
  14. </div>
  15. </md-scroll-view>
  16. </div>
  17. </template>
  18. <script>
  19. import {ScrollView, Toast} from 'mand-mobile'
  20. export default {
  21. name: 'scroll-view-demo-0',
  22. components: {
  23. [ScrollView.name]: ScrollView,
  24. },
  25. data() {
  26. return {
  27. list: 5,
  28. }
  29. },
  30. mounted() {
  31. window.ScrollViewTrigger0 = () => {
  32. this.addItems()
  33. }
  34. },
  35. methods: {
  36. $_onItemClick(i) {
  37. Toast.info(`Click ${i}`)
  38. },
  39. $_onScroll({scrollLeft, scrollTop}) {
  40. console.log(`[Mand Mobile ScrollView - demo0 - onScroll] scrollLeft: ${scrollLeft}, scrollTop: ${scrollTop}`)
  41. },
  42. addItems() {
  43. this.list += 5
  44. // 如果把autoReflow设置为false, 需调用reflowScroller
  45. this.$refs.scrollView.reflowScroller()
  46. },
  47. },
  48. }
  49. </script>
  50. <style lang="stylus">
  51. .md-example-child-scroll-view-0
  52. height 400px
  53. .scroll-view-item
  54. padding 30px 0
  55. text-align center
  56. font-size 28px
  57. font-family DINAlternate-Bold
  58. border-bottom .5px solid #efefef
  59. </style>

加载更多

请在移动设备中扫码预览
  1. <template>
  2. <div class="md-example-child md-example-child-scroll-view md-example-child-scroll-view-2">
  3. <md-scroll-view
  4. ref="scrollView"
  5. :scrolling-x="false"
  6. @endReached="$_onEndReached"
  7. >
  8. <div
  9. v-for="i in list"
  10. :key="i"
  11. class="scroll-view-list"
  12. >
  13. <p class="scroll-view-item">{{i}}</p>
  14. </div>
  15. <md-scroll-view-more
  16. slot="more"
  17. :is-finished="isFinished"
  18. >
  19. </md-scroll-view-more>
  20. </md-scroll-view>
  21. </div>
  22. </template>
  23. <script>
  24. import {ScrollView, ScrollViewMore} from 'mand-mobile'
  25. export default {
  26. name: 'scroll-view-demo-2',
  27. components: {
  28. [ScrollView.name]: ScrollView,
  29. [ScrollViewMore.name]: ScrollViewMore,
  30. },
  31. data() {
  32. return {
  33. list: 10,
  34. isFinished: false,
  35. }
  36. },
  37. methods: {
  38. $_onEndReached() {
  39. if (this.isFinished) {
  40. return
  41. }
  42. // async data
  43. setTimeout(() => {
  44. this.list += 5
  45. if (this.list >= 20) {
  46. this.isFinished = true
  47. }
  48. this.$refs.scrollView.finishLoadMore()
  49. }, 1000)
  50. },
  51. },
  52. }
  53. </script>
  54. <style lang="stylus">
  55. .md-example-child-scroll-view-2
  56. height 800px
  57. .scroll-view-item
  58. padding 30px 0
  59. text-align center
  60. font-size 32px
  61. font-family DINAlternate-Bold
  62. border-bottom .5px solid #efefef
  63. </style>

配合TabBar

请在移动设备中扫码预览
  1. <template>
  2. <div class="md-example-child md-example-child-scroll-view md-example-child-scroll-view-4">
  3. <md-scroll-view
  4. ref="scrollView"
  5. :scrolling-x="false"
  6. @scroll="$_onScroll"
  7. >
  8. <md-tab-bar
  9. slot="header"
  10. ref="tabBar"
  11. :default-index="activeBlockIndex - 1"
  12. :titles="tabBarTitles"
  13. :show-ink-bar="true"
  14. :key="activeBlockIndex"
  15. @indexChanged="$_onTabChange"
  16. ></md-tab-bar>
  17. <div
  18. v-for="i in category"
  19. :key="i"
  20. class="scroll-view-category"
  21. >
  22. <div
  23. v-for="j in list"
  24. :key="j"
  25. class="scroll-view-list"
  26. >
  27. <p class="scroll-view-item">{{`${i} - ${j}`}}</p>
  28. </div>
  29. </div>
  30. </md-scroll-view>
  31. </div>
  32. </template>
  33. <script>
  34. import {ScrollView, TabBar} from 'mand-mobile'
  35. export default {
  36. name: 'scroll-view-demo-3',
  37. components: {
  38. [ScrollView.name]: ScrollView,
  39. [TabBar.name]: TabBar,
  40. },
  41. data() {
  42. return {
  43. category: 5,
  44. list: 5,
  45. dimensions: [],
  46. scrollY: 0,
  47. isManual: false,
  48. }
  49. },
  50. computed: {
  51. tabBarTitles() {
  52. return this.dimensions.map((item, index) => {
  53. return index + 1
  54. })
  55. },
  56. activeBlockIndex() {
  57. let activeIndex = 1
  58. this.dimensions.forEach((dimension, index) => {
  59. if (this.scrollY >= dimension[0] && this.scrollY <= dimension[1]) {
  60. activeIndex = index + 1
  61. }
  62. })
  63. return activeIndex
  64. },
  65. },
  66. mounted() {
  67. // 如果内容发生变化,需重新初始化block和scroller
  68. this.$_initScrollBlock()
  69. // this.$refs.scrollView.reflowScroller()
  70. },
  71. methods: {
  72. $_initScrollBlock() {
  73. const blocks = this.$el.querySelectorAll('.scroll-view-category')
  74. let offset = 0
  75. Array.prototype.slice.call(blocks).forEach((block, index) => {
  76. const innerHeight = block.clientHeight
  77. this.$set(this.dimensions, index, [offset, offset + innerHeight])
  78. offset += innerHeight
  79. })
  80. },
  81. $_onScroll({scrollTop}) {
  82. if (!this.isManual) {
  83. this.scrollY = scrollTop
  84. }
  85. },
  86. $_onTabChange(index) {
  87. const offsetTop = this.dimensions[index][0]
  88. this.isManual = true
  89. this.$refs.scrollView.scrollTo(0, offsetTop, true)
  90. setTimeout(() => {
  91. this.scrollY = offsetTop
  92. this.isManual = false
  93. }, 500)
  94. },
  95. },
  96. }
  97. </script>
  98. <style lang="stylus">
  99. .md-example-child-scroll-view-4
  100. position relative
  101. height 800px
  102. .md-tab-bar
  103. box-shadow 0 2px 8px #f0f0f0
  104. .scroll-view-container
  105. padding-top 80px
  106. .scroll-view-item
  107. padding 30px 0
  108. text-align center
  109. font-size 32px
  110. border-bottom .5px solid #efefef
  111. </style>

下拉刷新 触发下拉刷新

请在移动设备中扫码预览
  1. <template>
  2. <div class="md-example-child md-example-child-scroll-view md-example-child-scroll-view-1">
  3. <md-scroll-view
  4. ref="scrollView"
  5. :scrolling-x="false"
  6. @refreshing="$_onRefresh"
  7. >
  8. <md-scroll-view-refresh
  9. slot="refresh"
  10. slot-scope="{ scrollTop, isRefreshActive, isRefreshing }"
  11. :scroll-top="scrollTop"
  12. :is-refreshing="isRefreshing"
  13. :is-refresh-active="isRefreshActive"
  14. ></md-scroll-view-refresh>
  15. <div
  16. v-for="i in list"
  17. :key="i"
  18. class="scroll-view-list"
  19. >
  20. <p class="scroll-view-item">{{i}}</p>
  21. </div>
  22. </md-scroll-view>
  23. </div>
  24. </template>
  25. <script>
  26. import {ScrollView, ScrollViewRefresh} from 'mand-mobile'
  27. export default {
  28. name: 'scroll-view-demo-0',
  29. components: {
  30. [ScrollView.name]: ScrollView,
  31. [ScrollViewRefresh.name]: ScrollViewRefresh,
  32. },
  33. data() {
  34. return {
  35. list: 5,
  36. }
  37. },
  38. mounted() {
  39. window.ScrollViewTrigger1 = () => {
  40. this.$refs.scrollView.triggerRefresh()
  41. }
  42. },
  43. methods: {
  44. $_onRefresh() {
  45. // async data
  46. setTimeout(() => {
  47. this.list += 5
  48. this.$refs.scrollView.finishRefresh()
  49. }, 2000)
  50. },
  51. },
  52. }
  53. </script>
  54. <style lang="stylus">
  55. .md-example-child-scroll-view-1
  56. height 800px
  57. .scroll-view-item
  58. padding 30px 0
  59. text-align center
  60. font-size 28px
  61. font-family DINAlternate-Bold
  62. border-bottom .5px solid #efefef
  63. </style>

粘性标题

请在移动设备中扫码预览
  1. <template>
  2. <div class="md-example-child md-example-child-scroll-view md-example-child-scroll-view-3">
  3. <md-scroll-view
  4. ref="scrollView"
  5. :scrolling-x="false"
  6. @scroll="$_onScroll"
  7. >
  8. <div
  9. v-for="i in category"
  10. :key="i"
  11. class="scroll-view-category"
  12. >
  13. <p class="scroll-view-category-title">{{ i }}</p>
  14. <div
  15. v-for="j in list"
  16. :key="j"
  17. class="scroll-view-list"
  18. >
  19. <p class="scroll-view-item">{{`${i} - ${j}`}}</p>
  20. </div>
  21. </div>
  22. </md-scroll-view>
  23. <p v-if="activeBlockIndex > 0" class="scroll-view-striky-title">{{ activeBlockIndex }}</p>
  24. </div>
  25. </template>
  26. <script>
  27. import {ScrollView} from 'mand-mobile'
  28. export default {
  29. name: 'scroll-view-demo-3',
  30. components: {
  31. [ScrollView.name]: ScrollView,
  32. },
  33. data() {
  34. return {
  35. category: 5,
  36. list: 5,
  37. dimensions: [],
  38. scrollY: 0,
  39. }
  40. },
  41. computed: {
  42. activeBlockIndex() {
  43. let activeIndex = -1
  44. this.dimensions.forEach((dimension, index) => {
  45. if (this.scrollY >= dimension[0] && this.scrollY <= dimension[1]) {
  46. activeIndex = index + 1
  47. }
  48. })
  49. return activeIndex
  50. },
  51. },
  52. mounted() {
  53. // 如果内容发生变化,需重新初始化block和scroller
  54. this.$_initScrollBlock()
  55. // this.$refs.scrollView.reflowScroller()
  56. },
  57. methods: {
  58. $_initScrollBlock() {
  59. const blocks = this.$el.querySelectorAll('.scroll-view-category')
  60. let offset = 0
  61. Array.prototype.slice.call(blocks).forEach((block, index) => {
  62. const innerHeight = block.clientHeight
  63. this.$set(this.dimensions, index, [offset, offset + innerHeight])
  64. offset += innerHeight
  65. })
  66. },
  67. $_onScroll({scrollTop}) {
  68. this.scrollY = scrollTop
  69. },
  70. },
  71. }
  72. </script>
  73. <style lang="stylus">
  74. .md-example-child-scroll-view-3
  75. position relative
  76. height 800px
  77. .scroll-view-striky-title
  78. position absolute
  79. top 0
  80. left 0
  81. right 0
  82. .scroll-view-category-title, .scroll-view-striky-title
  83. padding 10px 0
  84. text-align center
  85. font-size 32px
  86. font-family DINAlternate-Bold
  87. background-color #f0f0f0
  88. .scroll-view-item
  89. padding 30px 0
  90. text-align center
  91. font-size 32px
  92. border-bottom .5px solid #efefef
  93. </style>

API

ScrollView Props

属性说明类型默认值备注
scrolling-x水平滚动Booleantrue-
scrolling-y垂直滚动Booleantrue-
bouncing可回弹Booleantrue-
autoReflow 1.5.3+内容发生变化时自动重置滚动区域尺寸Booleanfalse当设置为false时,内容发生变化需手动调用reflowScroller
endReachedThreshold触发到达底部的提前量Number0单位px

ScrollViewRefresh Props

属性说明类型默认值备注
scroll-top距离顶部距离Number0单位px
is-refresh-active释放可刷新状态Booleanfalse-
is-refreshing刷新中状态Booleanfalse-
refresh-text待刷新文案String下拉刷新-
refresh-active-text释放可刷新文案String释放刷新-
refreshing-text刷新中文案String刷新中…-

ScrollViewMore Props

属性说明类型默认值备注
is-finished全部已加载Booleanfalse-
loading-text加载中文案String更多加载中…-
finished-text全部已加载文案String全部已加载-

ScrollView Slots

default

滚动区域内容插槽,当内容发生变化是,需要调用reflowScroller重置滚动区域,参考reflowScroller)

refresh

下拉刷新组件插槽,可如下使用slot-scoped获取相关滚动状态(不兼容slot-scoped时滚动状态也可通过事件中动态设置)

  1. <md-scroll-view-refresh
  2. slot="refresh"
  3. slot-scope="{ scrollTop, isRefreshActive, isRefreshing }"
  4. :scroll-top="scrollTop"
  5. :is-refreshing="isRefreshing"
  6. :is-refresh-active="isRefreshActive"
  7. ></md-scroll-view-refresh>
more

加载更多组件插槽

header

吸顶区域插槽

吸底区域插槽

ScrollView Methods

reflowScroller()

重置滚动区域,一般滚动区域中的内容发生变化之后需调用

scrollTo(left, top, animate = false)

滚动至指定位置

参数说明类型
left距左侧距离Number
top距顶部距离Number
animate使用动画Boolean
triggerRefresh()

触发下拉刷新

finishRefresh()

停止下拉刷新

finishLoadMore()

停止加载更多

ScrollView Events

@scroll({scrollLeft, scrollTop})

滚动事件

属性说明类型
scrollLeft距左侧距离Number
scrollTop距顶部距离Number
@refreshActive()

释放可刷新事件

@refreshing()

刷新中事件

@endReached()

滚动触底事件