vue 下拉刷新 上拉加载增多组件

<template lang="html">
    <div class="yo-scroll"
  :class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"
  @touchstart="touchStart($event)"
  @touchmove="touchMove($event)"
  @touchend="touchEnd($event)"
  @scroll="(onInfinite || infiniteLoading) ? onScroll($event) : undefined">
        <section class="inner" :style="{ transform: 'translate3d(0, ' + top + 'px, 0)' }">
            <header class="pull-refresh">
                <slot name="pull-refresh">
                    <span class="down-tip">下拉更新</span>
                    <span class="up-tip">松开刷新数据</span>
                    <span class="refresh-tip">加载中……</span>
                </slot>
            </header>
            <slot>
            </slot>
            <footer class="load-more">
                <slot name="load-more">
                    <span v-show="downFlag === false">上拉加载更多</span>
                    <span v-show="downFlag === true">加载中……</span>
                </slot>
            </footer>
            <div class="nullData" v-show="dataList.noFlag">暂无更多数据</div>
        </section>
    </div>
</template>
<script>
export default {
  props: {
    offset: {
      type: Number,
      default: 40 // 默认高度
    },
    enableInfinite: {
      type: Boolean,
      default: true
    },
    enableRefresh: {
      type: Boolean,
      default: true
    },
    dataList: {
      default: false,
      required: false
    },
    onRefresh: {
      type: Function,
      default: undefined,
      required: false
    },
    onInfinite: {
      type: Function,
      default: undefined,
      require: false
    }
  },
  data () {
    return {
      top: 0,
      state: 0,
      startX: 0,
      startY: 0,
      touching: false,
      infiniteLoading: false,
      downFlag: true // 用来显示是否加载中
    }
  },
  methods: {
    touchStart (e) {
      this.startY = e.targetTouches[0].pageY
      this.startX = e.targetTouches[0].pageX
      this.startScroll = this.$el.scrollTop || 0
      this.touching = true // 留着有用,不能删除
      this.dataList.noFlag = false
      this.$el.querySelector('.load-more').style.display = 'block'
    },
    touchMove (e) {
      if (!this.enableRefresh || this.dataList.noFlag || !this.touching) {
        return
      }
      let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
      if (diff > 0) e.preventDefault()
      this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)
      if (this.state === 2) { // in refreshing
        return
      }
      if (this.top >= this.offset) {
        this.state = 1
      } else {
        this.state = 0
      }
      let more = this.$el.querySelector('.load-more')
      if (!this.top && this.state === 0) {
        more.style.display = 'block'
      } else {
        more.style.display = 'none'
      }
    },
    touchEnd (e) {
      if (!this.enableRefresh) {
        return
      }
      this.touching = false
      if (this.state === 2) { // in refreshing
        this.state = 2
        this.top = this.offset
        return
      }
      if (this.top >= this.offset) { // do refresh
        this.refresh()
      } else { // cancel refresh
        this.state = 0
        this.top = 0
      }
      // 用于判断滑动是否在原地 ----begin
      let endX = e.changedTouches[0].pageX
      let endY = e.changedTouches[0].pageY
      let dy = this.startY - endY
      let dx = endX - this.startX
      // 如果滑动距离太短
      if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
//        console.log('滑动距离太短')
        return
      }
      // --------end--------
      if (!this.enableInfinite || this.infiniteLoading) {
        return
      }
      let outerHeight = this.$el.clientHeight
      let innerHeight = this.$el.querySelector('.inner').clientHeight
      let scrollTop = this.$el.scrollTop
      let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0
      let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
//      console.log(bottom + '__' + this.offset)
      if (bottom <= this.offset && this.state === 0) {
        this.downFlag = true
        this.infinite()
      } else {
        this.$el.querySelector('.load-more').style.display = 'none'
        this.downFlag = false
      }
    },
    onScroll (e) {
      if (!this.enableInfinite) {
        return
      }
      let outerHeight = this.$el.clientHeight // 屏幕内容区域 316
      let innerHeight = this.$el.querySelector('.inner').clientHeight  // inner height 923
      let scrollTop = this.$el.scrollTop  // 滚动条距顶部高度
      let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0 // 下拉刷新div高度
      let infiniteHeight = this.$el.querySelector('.load-more').clientHeight // 上拉加载更多div高度
      let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
      if (bottom + infiniteHeight - 1 <= infiniteHeight) {
        this.infinite()
      }
    },
    refresh () {
      this.state = 2
      this.top = this.offset
      setTimeout(() => {
        this.onRefresh(this.refreshDone)
      }, 300)
    },
    refreshDone () {
      this.state = 0
      this.top = 0
    },
    infinite () {
      this.infiniteLoading = true
      setTimeout(() => {
        this.onInfinite(this.infiniteDone)
      }, 2000)
    },
    infiniteDone () {
      this.infiniteLoading = false
    }
  }
}
</script>
<style>
  .yo-scroll {
    position: absolute;
    top: 2.78rem;
    right: 0;
    bottom: 0;
    left: 0;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    background-color: #fff
  }
  .yo-scroll .inner {
    position: absolute;
    top: -2rem;
     93%;
    transition-duration: 300ms;
    padding: 0 .25rem;
  }
  .yo-scroll .pull-refresh {
    position: relative;
    left: 0;
    top: 0;
     100%;
    height: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size:.3rem;
  }
  .yo-scroll.touch .inner {
    transition-duration: 0ms;
  }
  .yo-scroll.down .down-tip {
    display: block;
  }
  .yo-scroll.up .up-tip {
    display: block;
  }
  .yo-scroll.refresh .refresh-tip {
    display: block;
  }
  .yo-scroll .down-tip,
  .yo-scroll .refresh-tip,
  .yo-scroll .up-tip {
    display: none;
  }
  .yo-scroll .load-more {
    height: 1.5rem;
    text-align: center;
    line-height: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size:.3rem;
  }
  .nullData{
    font-size: .3rem;
    text-align: center;
    height: 1rem;
    line-height: 1rem;
  }
</style>

 根据具体项目调样式

页面引入 调用

 <Scroll :on-refresh="onRefresh" :on-infinite="onInfinite" :dataList="scrollData">
onRefresh (done) {
        // 执行刷新方法
        a()
        done() // call done
      },
// 加载更多方法
      onInfinite () {
        var _this = this
        let more = _this.$el.querySelector('.load-more')
       b()
      },    
原文地址:https://www.cnblogs.com/chaser-li/p/7918718.html