vue 虚拟列表滚动
需求来了
项目中有一个移动端的长列表,考虑再三,决定用虚拟列表优化一下,关于虚拟列表的实现网上有挺多方案的,为了省时省力还是决定采用成熟的第三方库,于是开始 github 之旅~
搜索关键字 vue virtual
,选取前两个 star hin 高的项目,展开看看对比对比看看哪个符合我的要求~是我的 the one~
对比之 vue-virtual-scroller
地址
[https://github.com/Akryum/vue-virtual-scroller] star: 6.2k
demo 地址
用法
<RecycleScroller
class="scroller"
:items="list"
:item-size="32"
key-field="id"
v-slot="{ item }"
>
<div class="user">
{{ item.name }}
</div>
</RecycleScroller>
注意事项:
- 官网的 demo 只提供了一次性加载大量数据的案例,并且亲测,如果自己定义无限加载的方法话,向上滚动会出现白屏。
对比之 vue-virtual-scroll-list
地址
[https://github.com/tangbc/vue-virtual-scroll-list] star: 3.1k
demo 地址
[https://tangbc.github.io/vue-virtual-scroll-list/#/]
用法
<virtual-list style="height: 360px; overflow-y: auto;" // make list scrollable
:data-key="'uid'"
:data-sources="items"
:data-component="itemComponent"
/>
注意事项
- 列表项需要以组件的方式传入
- 如果需要用原生页面的滚动事件,比如列表+上方固定栏的布局,可以开启
:page-mode="true"
,取消 scroller 的样式,原生。
对比结果:
经过对比最终决定使用 vue-virtual-scroll-list
,因为它在官方的 demo 中给出了无限加载的例子,且实测运行良好。而vue-virtual-scroller
则更适合用于前端分页加载大量数据的例子。
使用方式:
下面是基于 vue3 composition api 进行的封装,方便复用,如果是 vue2 的项目, 安装 @vue/composition-api
插件就可以毫无阻碍的使用 composition-api 啦!亲测没问题。
-
安装
npm i vue-virtual-scroll-list --save
-
main.ts
全局注册组件
// 全局注册 虚拟滚动的组件
import VirtualList from 'vue-virtual-scroll-list'
Vue.component('virtual-list', VirtualList)
- 封装公共逻辑
useVirtualInfinite.ts
import { ref, onMounted, Ref } from 'vue'
declare type returnType = {
loading: Ref<boolean>
onScrollToBottom: () => void
list: Ref<any[]>
}
export default function useVirtualInfinite (getListFn: ()=>Promise<any>) : returnType {
const loading = ref(false)
const list = ref<any[]>([])
const onScrollToBottom = () => {
getData()
}
// 获取数据方法
const getData = async () => {
if (!loading.value) {
loading.value = true
const { data } = await getListFn()
// eslint-disable-next-line
data.rows.forEach((item: any) => (item.id = new Date().getTime()));
list.value.push(...data.rows)
loading.value = false
}
}
// 挂载之后 获取 data
onMounted(() => {
getData()
})
return {
onScrollToBottom,
loading,
list
}
}
- 愉快使用
<template>
<virtual-list
:data-key="'id'"
:data-sources="list"
:data-component="commentItem"
:page-mode="true"
v-on:tobottom="onScrollToBottom"
>
<div slot="footer" class="loading-spinner text-center">加载中...</div>
</virtual-list>
</template>
<script>
const { list, onScrollToBottom } = useVirtualInfinite(getList)
return {
list,
onScrollToBottom
}
</script>