本文主要概述虚拟列表插件vue-birtual-scroll的一些使用心得,包括在element select 下拉框中的使用问题经验总结
官方文档地址:github.com/Akryum/vue-…
1. 安装包
npm i vue-virtual-scroller --save
2. vue2项目中使用
插件支持两种虚拟列表方法使用,一个是适用于固定高度的虚拟列表 { RecycleScroller },性能较高,占用的资源少速度快。
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
下面以下拉菜单为使用场景进行贴代码,业务场景就是后端一次性返回过多的商品数据列表,导致页面刚加载时一动不动,打开时也特别的卡。所以需要进行虚拟列表优化
<el-select
v-model="selectedProduct"
placeholder="选择讲解商品快速定位"
class="ui-el-select mr10"
popper-class="ui-poper-class"
size="small"
value-key="product_id"
filterable
remote
:loading="filterLoading"
:remote-method="remoteMethod"
@change="handleProductChange"
@visible-change="(visibel) => visibel && remoteMethod('')"
>
<RecycleScroller
v-slot="{ item }"
ref="recycleScrollRef"
class="relative h-full min-w-500"
:item-size="34" <!-- 一列的高度,单item高度 -->
:items="productFilterList" <!-- 绑定需要渲染的数组 -->
key-field="product_id" <!-- 唯一标识字段,不重复的id,没有的话item那边加个,index用index也行 -->
>
<el-option :key="item.product_id" :label="item.product_title" :value="item" class="h-34">
<div class="flex">
<img :src="item.image_url" alt="" width="30" height="30" />
<div class="relative ml-8 w-425 flex-1">
<text-over-tips :context="item.product_title" :calculated-offset="0"></text-over-tips>
</div>
</div>
</el-option>
</RecycleScroller>
<div v-if="!filterLoading && productFilterList.length == 0" class="text-center text-12 text-#fff">
暂无数据
</div>
</el-select>
这里由于使用的el-select中的filterable 下拉搜索 所以需要手动写remote-method进行数据刷新,否则会导致虚拟列表只隐藏对应项而列表中有大量空白
下面展示没有手动刷新数据时搜索的反应
<el-select
v-model="selectedProduct"
placeholder="选择讲解商品快速定位"
class="ui-el-select mr10"
popper-class="ui-poper-class"
size="small"
value-key="product_id"
filterable
@change="handleProductChange"
>
<RecycleScroller
v-slot="{ item }"
ref="recycleScrollRef"
class="relative h-full min-w-500"
:item-size="34" <!-- 一列的高度,单item高度 -->
:items="productFilterList" <!-- 绑定需要渲染的数组 -->
key-field="product_id" <!-- 唯一标识字段,不重复的id -->
>
<el-option :key="item.product_id" :label="item.product_title" :value="item" class="h-34">
<div class="flex">
<img :src="item.image_url" alt="" width="30" height="30" />
<div class="relative ml-8 w-425 flex-1">
<text-over-tips :context="item.product_title" :calculated-offset="0"></text-over-tips>
</div>
</div>
</el-option>
</RecycleScroller>
<div v-if="!filterLoading && productFilterList.length == 0" class="text-center text-12 text-#fff">
暂无数据
</div>
</el-select>
在使用el-select 的下拉搜索功能时,没有使用自定义过滤会导致el-options隐藏了但是虚拟列表还占着位置,因为vue-virtual-scroller 的实现原理是写
偏移进行列表优化
手动刷新代码,跟element官网示例一样加loading有加载的样
remoteMethod(query) {
clearTimeout(this.filterTimeout)
if (query !== '') {
this.filterLoading = true
this.filterTimeout = setTimeout(() => {
this.productFilterList = this.productList.filter((item) => {
return item.product_title.toLowerCase().indexOf(query.toLowerCase()) > -1
})
this.filterLoading = false
}, 200)
} else {
this.filterLoading = false
this.productFilterList = clone(this.productList)
}
}
也支持虚拟列表前后插槽
<RecycleScroller
class="relative h-full w-520"
:item-size="34" <!-- 一列的高度,单item高度 -->
:items="productFilterList" <!-- 绑定需要渲染的数组 -->
key-field="product_id" <!-- 唯一标识字段,不重复的id -->
>
<template #before> <!-- 虚拟列表循环前插槽 -->
<el-option label="全部商品" class="text-center" value="">全部商品</el-option>
</template>
<template #default="{ item }">
<el-option :label="item.product_title" :value="item.product_id">
<div class="flex">
<img :src="item.image_url" alt="" width="30" height="30" />
<div class="relative ml-8 w-440 flex-1">
<text-over-tips :context="item.product_title" :calculated-offset="0"></text-over-tips>
</div>
</div>
</el-option>
</template>
</RecycleScroller>
<div
v-if="!filterLoading && productFilterList.length == 0"
class="h-40 w-520 text-center text-12 leading-40 text-#fff"
>
暂无数据
</div>
</el-select>
# 不定高度时使用插件中另外一个组件 DynamicScroller,需要搭配 DynamicScrollerItem 组件使用,下面是使用案例
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
export default {
components: {
DynamicScroller,
DynamicScrollerItem
}
}
<DynamicScroller
:items="list" <!-- 绑定数组 -->
:min-item-size="180" <!-- 设置最小高度 -->
class="scroller h-full">
<template #default="{ item, active }">
<DynamicScrollerItem :item="item" :active="active" :data-index="item.id"> <!-- :data-index 跟之前的key-field类似,跟vue for 的key一样 -->
<!-- 这里放需要渲染的代码,以前写v-for 循环item 一样的写法 -->
</DynamicScrollerItem>
</template>
</DynamicScroller>