Vant2.x 是一个轻量、可靠的移动端组件库,于 2017 年开源。

BetterScroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件。它的核心是借鉴的 iscroll (opens new window)的实现,它的 API 设计基本兼容 iscroll,在 iscroll 的基础上又扩展了一些 feature 以及做了一些性能优化。


一、全局安装vant,better-scroll

npm i vant batter-scroll -S


二、scroll-list.vue

<template>
  <div ref="scrollRef">
    <div class="scroll-content">
      <slot></slot>

      <div class="bot-loading">
        <div v-if="isFinished">已经到底了...</div>
        <van-loading v-else size="14px" >正在加载...</van-loading>
      </div>
    </div>
  </div>
</template>

<script>
import { Loading } from 'vant'
import BScroll from 'better-scroll'

export default {
  name: 'betterScroll',
  components: {
    [Loading.name]: Loading
  },
  props: {
    /**
     * 1 滚动的时候会派发scroll事件,会截流。
     * 2 滚动的时候实时派发scroll事件,不会截流。
     * 3 除了实时派发scroll事件,在swipe的情况下仍然能实时派发scroll事件
     */
    scrollProbe: {
      type: Number,
      default: 1
    },
    openScroll: {
      type: Boolean,
      default: true
    },
    openPullUp: {
      type: Boolean,
      default: false
    },
    openPullDown: {
      type: Boolean,
      default: false
    },
    isFinished: {
      type: Boolean,
      default: true
    },
    // 滚动列表数据
    scrollDataList: {
      type: Array,
      default: null
    }
  },
  data () {
    return {
      scroll: null
    }
  },
  methods: {
    initScrollEffect () {
      const scrollRef = this.$refs.scrollRef
      if (!scrollRef) {
        console.warn('未初始化DOM实例')
        return false
      }

      const _bsScroll = this.scroll = new BScroll(scrollRef, {
        click: true,
        scrollY: true,
        probeType: this.scrollProbe
      })

      if (this.openScroll) {
        _bsScroll.on('scroll', (pos) => {
          this.$emit('scrollEvents', pos)
        })
      }

      // 是否派发滚动到底部事件,用于上拉加载
      if (this.openPullUp) {
        _bsScroll.on('scrollEnd', () => {
          const {
            y,
            maxScrollY
          } = _bsScroll
          if (y <= (maxScrollY + 50)) {
            this.$emit('pullUpEvents')
          }
        })
      }

      // 是否派发顶部下拉事件,用于下拉刷新
      if (this.openPullDown) {
        _bsScroll.on('touchEnd', (pos) => {
          if (pos.y > 100) {
            this.$emit('pullDownEvents')
          }
        })
      }
    },

    scrollRefresh () {
      this.scroll && this.scroll.refresh()
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.initScrollEffect()
    })
  },
  watch: {
    // 监听异步数据加载,重新计算高度,防止滚动失效
    scrollDataList () {
      setTimeout(() => {
        this.scrollRefresh()
      }, 100)
    }
  },
  destroyed () {
    if (this.scroll) {
      this.scroll.destroy()
    }
  }
}
</script>

<style scoped lang="scss">
.scroll-content .bot-loading {
  font-size: 12px;
  padding: 15px 0;
  color: $color-gray;
  text-align: center;
}
</style>


三、注册全局组件

// plugin.js

import scrollList from '@/components/scroll/scroll-list.vue'

const publicComponent = {
  install (vue) {
    vue.component('scroll-list', scrollList)
  }
}
export default publicComponent

// main.js

import publicComponent from '@/utils/plugin.js'
Vue.use(publicComponent)


四、引用组件

<template>
  <scroll-list
    class="scroll-list-box"
    :open-pull-up="true"
    :open-pull-down="true"
    @pullDownEvents="getNoticeList"
    @pullUpEvents="getNextPageHandle"
  >
    <ul>
      <li></li>
    </ul>
  </scroll-list>
</template>

<script>
export default {
  name: 'notice',
  data () {
    return {
      isLoading: false,
      isFinished: true,
      finishEndText: '已经到底了...'
    }
  },
  methods: {
    getNoticeList () {
      console.log('load-down')
    },

    getNextPageHandle () {
      console.log('load-up')
    }
  }
}
</script>