需求來了
項目中有一個移動端的長列表,考慮再三,決定用虛擬列表優化一下,關於虛擬列表的實現網上有挺多方案的,為了省時省力還是決定采用成熟的第三方庫,於是開始 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>