一个独立的组件全局:如果他可见,通知加载下一页数据,如果加载成功它自己就会被挤到下边—又变成了不可见了。
image.png
注意:它自己不保存数据

1.组件代码

src/components/xtx-infinite-loading.vue

  1. <template>
  2. <div class="xtx-infinite-loading" ref="container">
  3. <!-- 正在加载数据时显示 -->
  4. <div class="loading" v-if="isLoading">
  5. <span class="img"></span>
  6. <span class="text">正在加载...</span>
  7. </div>
  8. <!-- 数据全部加载完毕时显示 -->
  9. <div class="none" v-if="isFinished">
  10. <span class="text">亲,没有更多了</span>
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. import { ref } from 'vue'
  16. import { useIntersectionObserver } from '@vueuse/core'
  17. export default {
  18. name: 'XtxInfiniteLoading',
  19. emits: ['load'],
  20. props: {
  21. // 是否在加载中
  22. isLoading: {
  23. type: Boolean,
  24. default: false
  25. },
  26. // 数据全部加载完毕
  27. isFinished: {
  28. type: Boolean,
  29. default: false
  30. }
  31. },
  32. setup (props, { emit }) {
  33. const container = ref(null)
  34. useIntersectionObserver(
  35. container,
  36. ([{ isIntersecting }], dom) => {
  37. if (isIntersecting) {
  38. // 只有数据不在加载中且还没全部结束时才触发load事件
  39. if (props.isLoading === false && props.isFinished === false) {
  40. emit('load')
  41. }
  42. }
  43. },
  44. {
  45. threshold: 0
  46. }
  47. )
  48. return { container }
  49. }
  50. }
  51. </script>

2.组件使用

sub.vue

  1. <!-- 列表 -->
  2. <div class="sort-list-container">
  3. <GoodsItem v-for="good in goodsList" :key="good" :good="good" />
  4. </div>
  5. <!-- 上拉加载 -->
  6. <XtxInfiniteLoad @load="loadData" :isFinished="isFinished" :isLoading="isLoading"/>
  7. setup(){
  8. //这里使用了逻辑抽离
  9. const { subCate } = useSubCate()
  10. + const { isFinished, isLoading, loadData, goodsList, hFilterChange, hSortChange } = useLoadData()
  11. + return { subCate, goodsList, hFilterChange, hSortChange, loadData, isLoading, isFinished }
  12. }

3.修改useLoaddata

  1. const useLoadData = () => {
  2. const route = useRoute()
  3. // 请求参数
  4. let reqParams = {
  5. categoryId: route.params.id,
  6. inventory: null, // 是否只显示有库存
  7. onlyDiscount: null, // 是否只显示有优惠
  8. brandId: null, // 品牌名称
  9. attrs: [], // 商品属性
  10. sortField: null, // 排序类别
  11. sortMethod: null, // 排序的方式
  12. page: 1,
  13. pageSize: 20
  14. }
  15. const goodsList = ref([]) // 保存查询结果
  16. + const isLoading = ref(false)
  17. + const isFinished = ref(false)
  18. const loadData = () => {
  19. + isLoading.value = true
  20. findSubCategoryGoods(reqParams).then(data => {
  21. console.log('findSubCategoryGoods', data)
  22. // 新数据要追加到数组中
  23. + goodsList.value.push(...data.result.items)
  24. // 页码加1
  25. + reqParams.page++
  26. // 判断是否加载完成
  27. + if (data.result.items.length === 0) {
  28. + isFinished.value = true
  29. }
  30. + isLoading.value = false
  31. })
  32. }
  33. const hFilterChange = (filterParam) => {
  34. console.log('父组件收到了筛选条件', filterParam)
  35. // 更新条件
  36. // reqParams.brandId = filterParam.brandId
  37. // reqParams.attrs = filterParam.attrs
  38. reqParams = { ...reqParams, ...filterParam }
  39. // 重发请求
  40. loadData()
  41. }
  42. const hSortChange = (sortParam) => {
  43. console.log('父组件收到了排序条件', sortParam)
  44. // 更新条件
  45. // reqParams.inventory = sortParam.inventory
  46. // reqParams.onlyDiscount = sortParam.onlyDiscount
  47. reqParams = { ...reqParams, ...sortParam }
  48. // 重发请求
  49. loadData()
  50. }
  51. loadData()
  52. return { isFinished, isLoading, goodsList, hFilterChange, hSortChange, loadData }
  53. }