vue3.0项目中手动封装加载更多数据(常见)

67 篇文章 7 订阅
25 篇文章 2 订阅

技术点  Vue官方工具库 (仅限vue3.0使用)中的 useIntersectionObserver  

使用场景:在一些购物平台中,往往都会看见下滑商品的时候当滑倒底部就会去请求最新的数据,和数据懒加载和图片懒加载很类似

 一、模拟数字实现

 默认数字为60个数字 当滚到第60个数字时模拟请求20个数字 

 封装组件

npm i @vueuse/core
<template>
  <div class="xtx-infinite-loading" ref="container">
    <!-- 正在加载数据时显示 -->
    <div class="loading" v-if="isLoading">
      <span class="img"></span>
      <span class="text">正在加载...</span>
    </div>
    <!-- 数据全部加载完毕时显示 -->
    <div class="none" v-if="isFinished">
      <span class="text">亲,没有更多了</span>
    </div>
  </div>
</template>
<script>
import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
export default {
  name: 'xtxInfiniteLoading',
  props: {
    // 是否在加载中
    isLoading: {
      type: Boolean,
      default: false
    },
    // 数据全部加载完毕
    isFinished: {
      type: Boolean,
      default: false
    }
  },
  setup (props, { emit }) {
    const container = ref(null)
    const { stop } = useIntersectionObserver(container, ([{ isIntersecting }]) => {
      if (isIntersecting) {
        // 双重 判断 缺一不可
        if (props.isFinished === false && props.isLoading === false) {
          emit('doLoading')
        }
      }
    })
    return { container, stop }
  }
}
</script>

<style scoped lang='less'>
.xtx-infinite-loading {
  .loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 200px;
    .img {
      width: 50px;
      height: 50px;
      background: url('~@/assets/images/load.gif') no-repeat center / contain;
    }
    .text {
      color: #999;
      font-size: 16px;
    }
  }
  .none {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 200px;
    .text {
      color: #999;
      font-size: 16px;
    }
  }
}
</style>

分析 

变量 
    isLoading 是否在加载中
    isFinished 数据全部加载完毕

 DOM:

如果isLoading 为true 显示  加载状态

如果 isFinished 为true  显示 加载完毕

js :

要操作的DOM元素 

  const container = ref(null)

使用监听
    const { stop } = useIntersectionObserver(container, ([{ isIntersecting }]) => {

如果当前监听的元素可见
      if (isIntersecting) {
        // props传递时异步的  双重 判断 缺一不可 当没有加载完毕 并且 没有正在加载  
        if (props.isFinished === false && props.isLoading === false) {

抛出事件给父组件
          emit('doLoading')
        }
      }
    })

测试

<template>
 <p v-for="i in list" :key="i" style="margin-left:50px"> {{i}} </p>
   <xtxInfiniteLoading @doLoading="doLoading" :isLoading="isLoading" :isFinished="isFinished"></xtxInfiniteLoading>
</template>
<script>
import { ref } from 'vue'
export default {
  setup () {
    const list = ref(60)
    const isLoading = ref(false)
    const isFinished = ref(false)
    const doLoading = () => {
      isLoading.value = true
      setTimeout(() => {
        list.value += 20
        isLoading.value = false
        if (list.value >= 100) {
          isFinished.value = true
        }
      }, 1000)
    }
    return { list, doLoading, isLoading, isFinished }
  }
}
</script>

 DOM:

循环list中的数据,并且接收子组件传过来的数据

JS

调用子组件抛出来的事件,加载完毕后把正在加载设为false  当list数据大于等于100  把加载完成设为true,也就是说当大于100的时候不再执行

  if (props.isFinished === false && props.isLoading === false) {  子组件中判断如果加载和加载完毕都为false才执行
          emit('doLoading')
        }

项目中例子

封装的组件不用修改,直接在父组件中写代码

<template> 
<xtxInfiniteLoading @doLoading="doLoading" :isFinished="isFinished" :isLoading="isLoading" ></xtxInfiniteLoading>
</template>
<script>
import { ref } from 'vue'
export default {
  setup () {
    const isLoading = ref(false)
    const isFinished = ref(false)
    const doLoading = () => {
        isLoading.value = true
      findSubCategoryGoods(reqParams).then(res => {
        //思路①
        if (res.result.items.length) {
          isFinished.value = false
          reqParams.page++
        } else {
          isFinished.value = true
        }
        goodList.value.push(...res.result.items)

        //  思路②
        // isLoading.value = false
        // goodList.value.push(...res.result.items)
        // reqParams.page++
        // if (!res.result.items.length) {
        //   isFinished.value = true
        // }
      })
    }
      return {doLoading, isLoading, isFinished }
  }
}
</script>

 DOM:当浏览到可视区域 封装的子组件触发事件 给父组件  父组件接受后就回去调用doLoading事件

JS: 触发doLoading事件

1.  先把isLoading  变量设为true代表正在加载 

2. 调用请求之后 if判断 如果返回的长度不为0 那么代表后台一直有数据 

3. if{  把isLoading 状态改为false代表加载完了,页数++  }

4.else 代表后台的数据没有了 把isFinished 变量设为true 代表全部执行完了

5.每次调用函数 都把最新的数据添加到 goodList中 注意(一开始获取和添加不是同一个方法 只是同一个API

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值