简单封装vue移动端上拉加载更多

2020-07-24  本文已影响0人  武汉前端任金杰

<template lang="html">

  <div class="load-moudle" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchend($event)">

    <slot></slot>

    <footer class="load-more">

      <slot name="load-more">

        <div class="more-tip" v-if="pullUpState==1">

          <span class="more-text">{{pullUpInfo.moreText}}</span>

        </div>

        <div class="loading-tip" v-if="pullUpState==2">

          <span class="loading-icon"></span>

          <span class="loading-text">{{pullUpInfo.loadingText}}</span>

        </div>

        <div class="no-more-tip" v-if="pullUpState==3">

          <span class="connecting-line"></span>

          <span class="no-more-text">{{pullUpInfo.noMoreText}}</span>

          <span class="connecting-line"></span>

        </div>

      </slot>

    </footer>

  </div>

</template>

<script>

export default {

  props: {

    parentPullUpState: {

      default: 0

    },

    onInfiniteLoad: {

      type: Function,

      require: false

    }

  },

  data () {

    return {

      top: 0,

      pullUpState: 0, // 1:上拉加载更多, 2:加载中……, 3:我是有底线的

      isLoading: false, // 是否正在加载

      pullUpInfo: {

        moreText: '上拉加载更多',

        loadingText: '加载中...',

        noMoreText: '我是有底线的'

      },

      startX: 0,

      startY: 0,

      endX: 0,

      endY: 0

    }

  },

  created () {

    // console.log(this.pullUpState)

  },

  methods: {

    /**

     * 触摸开始,手指点击屏幕时

     * @param {object} e Touch 对象包含的属性

     */

    touchStart (e) {

      this.startX = e.touches[0].pageX

      this.startY = e.touches[0].pageY

    },

    /**

     * 接触点改变,滑动时

     * @param {object} e Touch 对象包含的属性

     */

    touchMove (e) {

      this.endX = e.changedTouches[0].pageX

      this.endY = e.changedTouches[0].pageY

      let direction = this.getSlideDirection(this.startX, this.startY, this.endX, this.endY)

      switch (direction) {

        case 0:

          // console.log('没滑动')

          break

        case 1:

          // console.log('向上')

          this.scrollToTheEnd()

          break

        case 2:

          // console.log('向下')

          break

        case 3:

          // console.log('向左')

          break

        case 4:

          // console.log('向右')

          break

        default:

      }

    },

    /**

     * 触摸结束,手指离开屏幕时

     * @param {object} e Touch 对象包含的属性

     */

    touchend (e) {

      this.isLoading = false

    },

    /**

     * 判断滚动条是否到底

     */

    scrollToTheEnd () {

      let innerHeight = document.querySelector('.load-moudle').clientHeight

      // 变量scrollTop是滚动条滚动时,距离顶部的距离

      let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop

      // 变量scrollHeight是滚动条的总高度

      let scrollHeight = document.documentElement.clientHeight || document.body.scrollHeight

      // 滚动条到底部的条件

      if (scrollTop + scrollHeight >= innerHeight) {

        if (this.pullUpState !== 3 && !this.isLoading) {

          this.infiniteLoad()

        }

        // console.log('距顶部' + scrollTop + '滚动条总高度' + scrollHeight + '内容高度' + innerHeight)

      }

    },

    /**

     * 上拉加载数据

     */

    infiniteLoad () {

      if (this.pullUpState !== 0) {

        this.pullUpState = 2

        this.isLoading = true

        this.onInfiniteLoad(this.infiniteLoadDone)

      }

    },

    /**

     * 加载数据完成

     */

    infiniteLoadDone () {

      this.pullUpState = 1

    },

    /**

     * 返回角度

     */

    getSlideAngle (dx, dy) {

      return Math.atan2(dy, dx) * 180 / Math.PI

    },

    /**

     * 根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动

     * @param {number} startX X轴开始位置

     * @param {number} startY X轴结束位置

     * @param {number} endX Y轴开始位置

     * @param {number} endY Y轴结束位置

     */

    getSlideDirection (startX, startY, endX, endY) {

      let dy = startY - endY

      let dx = endX - startX

      let result = 0

      // 如果滑动距离太短

      if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {

        return result

      }

      let angle = this.getSlideAngle(dx, dy)

      if (angle >= -45 && angle < 45) {

        result = 4

      } else if (angle >= 45 && angle < 135) {

        result = 1

      } else if (angle >= -135 && angle < -45) {

        result = 2

      } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {

        result = 3

      }

      return result

    }

  },

  watch: {

    parentPullUpState (curVal, oldVal) {

      this.pullUpState = curVal

    }

  }

}

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->

<style scoped>

.load-more {

  width: 100%;

  color: #c0c0c0;

  background: #fafafa;

  font-size: 14px;

}

.no-more-text {

  display: block;

  width: 150px;

}

.more-tip,

.loading-tip,

.no-more-tip {

  display: flex;

  align-items: center;

  justify-content: center;

  height: 150px;

}

.load-moudle .loading-icon {

  display: inline-flex;

  width: 35px;

  height: 35px;

  background: url('../../assets/loading.png') no-repeat;

  background-size: cover;

  margin-right: 5px;

  animation: rotating 2s linear infinite;

}

@keyframes rotating {

  0% {

    transform: rotate(0deg);

  }

  100% {

    transform: rotate(1turn);

  }

}

.connecting-line {

  display: inline-flex;

  width: 150px;

  height: 2px;

  background: #ddd;

  margin-left: 20px;

  margin-right: 20px;

}

</style>

在父组件---引入使用:

<v-reload

        :on-infinite-load="onInfiniteLoad"

        :parent-pull-up-state="infiniteLoadData.pullUpState"

      >

<''列表内容‘’>

</v-reload>

data(){

return{

infiniteLoadData: {

      initialShowNum: 3, // 初始显示多少条

      everyLoadingNum: 3, // 每次加载的个数

      pullUpState: 2, // 子组件的pullUpState状态

      pullUpList: [], // 上拉加载更多数据的数组

      showPullUpListLength: this.initialShowNum // 上拉加载后所展示的个数

    },

}

merhods:{

onInfiniteLoad (done) {

      console.log(done, this.infiniteLoadData.pullUpState)

      if (this.infiniteLoadData.pullUpState === 1) {

        this.getSiteInfo()    //获取列表数据的函数

      }

      done()

    }

上一篇下一篇

猜你喜欢

热点阅读