Vue 无限滚动加载列表

Vue 无限滚动加载列表

Flying
2020-06-08 / 0 评论 / 104 阅读 / 正在检测是否收录...

最近按照产品的要求对列表进行了重构,把以前的普通的翻页列表改成了无限滚动加载列表——滚动至底部时,加载更多数据——和移动应用的翻页效果类似。借助 vue-infinite-scroll 组件很快就实现了无限滚动加载功能。

scroll-vue.svg

发现问题

酷是很酷。但是问题也来了:需要改动分页的页面还不少:图片列表、声音列表、视频列表都需要改动。使用 “CV”大法,工作量不算很大,然而“CV”大法的代码很难维护。有没有办法复用这个逻辑呢?我们先前的分页采用混入(mixin)来复用的。实践证明这种方法不是太靠谱。

  • 命名空间冲突:模块多了,不严格遵循命名规范,混入很容易导致命名冲突。
  • 数据来源不清晰的:不小心会误删代码。

记得有个刚来的小伙伴对项目代码不是很清楚,他看到一个页面有很多属性和方法都没有引用或调用,就自作主张地将“多余”代码删了,结果报错了,他不知道我们的代码使用了混入。

分析问题

有没有其他办法可以实现无限滚动加载复用?因为前不久系统学习了 Vue 插槽,尤其对作用域插槽影响深刻。我就琢磨着使用 <slot> 来实现可复用的无限滚动加载列表。

基本原理

  • 我们可以像对组件传递 props 那样,向一个插槽的出口上插槽 props 对象:
  • 当需要接收插槽 props 时,默认插槽通过子组件标签上的 v-slot 指令,直接接收到了一个插槽 props 对象:
  • 子组件传入插槽的 props 作为了 v-slot 指令的值,可以在插槽内的表达式中访问。

v-slot.png

注意:具名作用域插槽的工作方式也是类似的,插槽 props 可以作为 v-slot 指令的值被访问到:v-slot:name="slotProps"。可以在 v-slot 中使用解构。

我们可以定义一个 InfiniteScrollList 组件,它只包括了逻辑(比如无限滚动加载)而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件( ImageList、AudioList 等组件),这样就是很好的实现了代码的重用。我们将这种类型的组件和 React 中的容器组件类似。

InfiniteScrollList 组件实现

新建 InfiniteScrollList.vue,添加下述代码:

  • template
<div
  class="infinite-scroll"
  v-infinite-scroll="loadMore"
  :infinite-scroll-disabled="!busy"
>
  <slot :list="list" />
  <transition name="fade">
    <div v-show="!busy" class="loader">{{ message }}</div>
  </transition>
  </div>
  • script
import axios from "axios";

export default {
  name: "InfiniteScrollList",
  data() {
    return {
      busy: false,
      finished: false,
      list: [],
      total: 0,
      param: {
        offset: 0,
        limit: 30,
        type: 1,
      },
    };
  },
  computed: {
    message() {
      return !this.finished ? "Load more..." : "No more~";
    },
  },
  methods: {
    loadMore() {
     // ...
  },
};
  • style
.loader {
  position: fixed;
  width: 100%;
  bottom: 0;
  background-color: #eeeeee;
  text-align: center;
  font-size: 12px;
  line-height: 36px;
}

.fade-enter-active {
  animation: fade-in 0.5s;
}

.fade-leave-active {
  animation: fade-in 2s 0.5s reverse;
}

@keyframes fade-in {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 50;
  }
  100% {
    opacity: 100;
  }
}

实现 ImageList 组件

新建 InfiniteScrollList.vue,添加下述代码:

<template>
  <InfiniteScrollList v-slot="{ list }">
    <ul>
      <li v-for="(item, index) in list" :key="index">
        {{ item.name }} -- {{ new Date(item.create * 1000) | formatDate }}
      </li>
    </ul>
  </InfiniteScrollList>
</template>
//...

其他组件类似,可访问 codesandbox 查看项目代码

总结

本文简述了怎样使用作用域插槽自定义一个可高级列表组件,它只封装了可重用的逻辑而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件。

1

评论 (0)

取消