本文主要是介绍H5移动端 Vue3 + vue-virtual-scroller 实现长列表性能优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 安装 vue-virtual-scroller
- 引入
- 📢注意事项
- 使用
- 基础使用
- 上拉加载
- 下拉刷新
移动端在渲染长列表时 大量dom节点的渲染和重绘重排会导致页面卡顿、滚动不流畅、设备耗电加快、影响移动设备电池寿命等性能问题
这里分享使用【虚拟滚动】方案进行长列表优化,以Vue3为例,推荐使用 vue-virtual-scroller
先列举 vue-virtual-scroller
相关官方文档帮助学习
- 官方文档
- Live demo
- Live demo 源码
- Video demo
安装 vue-virtual-scroller
npm install --save vue-virtual-scroller@next
yarn add vue-virtual-scroller@next
引入
安装所有组件:
import VueVirtualScroller from 'vue-virtual-scroller'app.use(VueVirtualScroller)
按需引入组件:
import { RecycleScroller } from 'vue-virtual-scroller'app.component('RecycleScroller', RecycleScroller)
引入样式文件
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
📢注意事项
- 整个列表的高度要写死,不然会将整改列表作为可视区域,会出现渲染全部数据而不是只渲染可视区域的问题;
这里推荐使用flex: 1;
实现,比height: calc(100vh - 30vw);
更优雅、更易维护 - 使用
-webkit-overflow-scrolling: touch;
开启硬件加速,ios高版本自带 - 使用
overscroll-behavior: none;
禁用iOS回弹效果
使用
使用 DynamicScroller
组件渲染不确定高度的组件
基础使用
<div class="content-wrap"><DynamicScroller:items="dataList":min-item-size="160"key-field="id"class="virtual-scroller"><template #default="{ item, index, active }"><DynamicScrollerItem:item="item":active="active":size-dependencies="[item.status, item.type]":data-index="index"class="virtual-scroller-item"><!-- 渲染组件 --><TaskItem :data="item" /></DynamicScrollerItem></template></DynamicScroller>
</div>
.icc__container {height: 100vh;display: flex;flex-direction: column;box-sizing: border-box;.icc__content-wrap {flex: 1;.virtual-scroller {/* 开启硬件加速 -webkit-overflow-scrolling: touch; ios高版本自带 */-webkit-overflow-scrolling: touch;/* 禁用回弹效果 */overscroll-behavior: none;height: 100%;}}
}
上拉加载
vant List
+ DynamicScroller
会导致连续触发 vant List
load 事件,所以只能手写上拉加载
- 监听
DynamicScroller
滚动事件,如果当前距离顶部的值加上可视区域的值大于等于总高度,则滚动条触底,加载更多 - 使用
DynamicScroller
after
插槽,定义加载中、加载完成、加载失败等状态
<div class="content-wrap"><DynamicScroller:items="dataList":min-item-size="160"key-field="id"class="virtual-scroller"@scroll="handleDynamicScrollerScroll"><template #default="{ item, index, active }"><DynamicScrollerItem:item="item":active="active":size-dependencies="[item.status, item.type]":data-index="index"class="virtual-scroller-item"><!-- 渲染组件 --><TaskItem :data="item" /></DynamicScrollerItem></template><template #after><div class="after"><van-loading v-show="loadMoreLoading">加载中...</van-loading><span v-show="finished">没有更多了</span><span v-show="loadError" @click="handleLoadMore">请求失败,点击重新加载</span></div></template></DynamicScroller>
</div>
// 上拉loading
const loadMoreLoading = ref<boolean>(false)
// 没有更多数据了
const finished = ref<boolean>(false)
// 加载失败
const loadError = ref<boolean>(false)// 实现上拉加载
const handleDynamicScrollerScroll = (e: Event) => {// 距顶部const scrollTop = (e.target as HTMLDivElement)?.scrollTop || 0// 可视区高度const clientHeight = (e.target as HTMLDivElement).clientHeight || 0// 滚动条总高度const scrollHeight = (e.target as HTMLDivElement)?.scrollHeight || 0// 触底距离const offset = 300// 如果当前距离顶部的值加上可视区域的值大于等于总高度,则滚动条触底if (scrollTop + clientHeight >= scrollHeight - offset) {if (!loadMoreLoading.value && !finished.value && !loadError.value) {console.log('滚动到底部了')loadMoreLoading.value = truehandleLoadMore()}}
}
下拉刷新
使用 vant PullRefresh
实现下拉刷新
如果直接用 vant PullRefresh
包裹虚拟滚动,会导致无法向下滑动,任何位置下拉都会触发下拉刷新。
解决方案:
1. `vant PullRefresh` 中有 `disabled` 选项,可以禁用下拉刷新,默认设置为 `false`
2. 监听滚动条滚动事件中的 `scrollTop`,
3. 如果 `scrollTop` 小于4,则将 `disabled` 变为 `false`
4. 否则将 `disabled` 变为 `true`
<template><div class="container"><van-pull-refreshv-model="refreshLoading"@refresh="handlerefresh":disabled="disabledPullRefresh"class="content-wrap"><template v-if="dataList.length > 0"><DynamicScroller:items="dataList":min-item-size="160"key-field="id"class="virtual-scroller"id="virtual-scroller"@scroll="handleDynamicScrollerScroll"><template #default="{ item, index, active }"><DynamicScrollerItem:item="item":active="active":size-dependencies="[item.status, item.type]":data-index="index"class="virtual-scroller-item"><!-- 渲染组件 --><TaskItem :data="item" /></DynamicScrollerItem></template><template #after><div class="after"><van-loading v-show="loadMoreLoading">加载中...</van-loading><span v-show="finished">没有更多了</span><span v-show="loadError" @click="handleLoadMore">请求失败,点击重新加载</span></div></template></DynamicScroller></template><van-emptyv-elseimage="./no_data.png"description="暂无匹配数据":image-size="['60vw', 'auto']"class="h-80vh"/></van-pull-refresh></div><van-back-top target="#virtual-scroller" />
</template>
// 下拉loading
const refreshLoading = ref<boolean>(false)
// 禁用下拉刷新
const disabledPullRefresh = ref(false)
// 上拉loading
const loadMoreLoading = ref<boolean>(false)
// 没有更多数据了
const finished = ref<boolean>(false)
// 加载失败
const loadError = ref<boolean>(false)
// 实现上拉加载
const handleDynamicScrollerScroll = (e: Event) => {// 距顶部const scrollTop = (e.target as HTMLDivElement)?.scrollTop || 0// 可视区高度const clientHeight = (e.target as HTMLDivElement).clientHeight// 滚动条总高度const scrollHeight = (e.target as HTMLDivElement)?.scrollHeightconst offset = 300// 如果直接用 `vant PullRefresh` 包裹虚拟滚动,会导致无法向下滑动,任何位置下拉都会触发下拉刷新。// 控制是否开启下拉刷新if (scrollTop <= 4) {disabledPullRefresh.value = false} else {disabledPullRefresh.value = true}// 如果当前距离顶部的值加上可视区域的值大于等于总高度,则滚动条触底if (scrollTop + clientHeight >= scrollHeight - offset) {if (!loadMoreLoading.value && !finished.value && !loadError.value) {console.log('滚动到底部了')loadMoreLoading.value = truehandleLoadMore()}}
}
兄弟们,上面的代码在项目中踩坑实测过了!!
源码就不贴了😄
这篇关于H5移动端 Vue3 + vue-virtual-scroller 实现长列表性能优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!