上拉加载更多 vue.js

643 阅读1分钟

手机端上拉加载页面,在vue.js框架里面实现,因为用其他包的话,其实用不到那么多功能,都不好意思用包-_- ---所有的代码都有注释说明

data

data () {
    // 因为这里的有三个tab,所以先定义一个循环,主要是在切换的时候改变文字以及传参,
   // 如果你只有一个列表,可以忽略
    const tabList = [
      {
        text: '本月收入',
        img: 'monthIncome',
        rankType: 1, 
        dateType: 1, 
      },
      {
        text: '总收入',
        img: 'totalIncome',
        rankType: 2, 
        dateType: 2, 
      },
      {
        text: '最高速度',
        img: 'highSpeed',
        rankType: 3, 
        dateType: 3, 
      },
    ]
    // size是固定的,为了做到修改一次size,就能改变所有地方的size,所以抽出来定义
    const size = 2
    return {
      tabList,
      currentIndex: 0,
      rankList: [], // 数据列表
      size,
      rankParams: {
        rankType: 1,
        dateType: 1,
        page: 1,
        size,
      },
      more: true, // 是否还有分页的数据
      total: 0, // 数据总条数
      triggerDistance: 10, // 滚动加载阈值
      isLastData: false, // 是不是最后一页
    }
  },

template

tab的代码 (有删减,只留基本解构,保留@click="changeRankType(item,index))

 <div v-for="(item,index) in tabList"  :key="index" @click="changeRankType(item,index)">
    <img 
        class="month-income"
        :src="require(`@/assets/image/starMine/${item.img}.png`)"
    >    
 </div>

列表的代码

<div class="ranking-list-bg">
  <div class="ranking-list" ref="rankingRef" @touchend="touchEnd">
    <div class="ranking-list-info" v-for="(item,index) in rankList" :key="index">
      <commonItem
        :currentIndex="currentIndex"
        :index="index"
        :is-mine="false"
        :user-info="item.user"
        :user-value="item.value"
      />
    </div>
    <!--最后一条-->
    <div v-show="this.rankParams.page !== 1 && isLastData"  class="rank-last-data">
      <div class="rank-last-data-line"></div>
      <div class="rank-last-data-text">到底啦~</div>
    </div>
  </div>
</div>

这里最重要的就是ref="rankingRef" @touchend="touchEnd",后续会用到

methods && mounted

 async mounted () {
    this.getRankingList()
  },
  methods: {
    async getRankingList () {
        const { ranks, total } = await getMineRankApi(this.token, this.rankParams)
        // 每一次下拉都要把数据push进去
        this.rankList.push(...ranks)
        // 拿到总条数
        this.total = total
        // 如果目前的页数小于或者等于(总页数/美页条数),表示还可以加载,反之,不能
        this.more = this.rankParams.page <= (this.total / this.rankParams.size)
        // 当页数大于或者等于(总页数/美页条数), 可以显示已经到底了
        if (this.rankParams.page >= +(this.total / this.rankParams.size)) {
          this.isLastData = true
        }
    },
    // 切换tab
    changeRankType ({ rankType, dateType }, index) {
      // 因为三个tab实际上用的是同一个接口,在切换时,必须将page,size重置,将其他参数动态写入
      // 必须将是否到底进行重置为false
      // 必须将列表进行重置为空数组
      this.currentIndex = index
      this.isLastData = false
      this.rankParams = {
        rankType,
        dateType,
        page: 1,
        size: this.size,
      }
      this.rankList = []
      this.getRankingList()
    },
    touchEnd () {
      // 如果不能下拉页数超过总页数,return
      if (!this.more) {
        return
      }
      // 元素的内容垂直滚动的高度 + 元素可视高度 + 阈值 > 元素的的所有的高度(卷起来+ 可视)
      if (this.$refs.rankingRef.scrollTop 
      +this.$refs.rankingRef.offsetHeight
      + this.triggerDistance > this.$refs.rankingRef.scrollHeight) {
        this.rankParams.page += 1
        this.getRankingList()
      }
    },
  },

参考scrollTop offsetHeight scrollHeight

这里我觉得最重要的就是什么时候进行滑动? scrollTop表示的是元素滚动的高度,offsetHeight表示元素的高度,scrollHeight表示的是总高度(包含卷起),那么如果scrollTop + offsetHeight = scrollHeight,表示我手已经滑倒最底部了,但是不可能只有在最底部才能滑动,所以要加上一个阈值,给他一个滑动的区间.

当我没有滚动时,scrollTop = 0, 没有分页但是元素超出一屏幕的时候,scrollTop + offsetHeight < scrollHeight

阈值越大,表示在越上面就能加载到下一页

css

.ranking-list {
   height: 900px; // 这里最好给一个高度
   overflow: scroll;
}

效果

下拉.gif