- 作者:老汪软件技巧
- 发表时间:2024-09-27 15:01
- 浏览量:
前言
《爱在黎明破晓前》
我见了你一面,便用一生去怀念
三部曲讲解了青春、中年、老年的爱情,触动挺多的。
一、前言
今天像往常一样,开开心心的打代码编程。
突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。
于是便有了今天这篇文章,一起来探讨一下。
当然,你也可以当做面试题。
二、分析
在我们的移动端,表单通过配置渲染表单类型。
如果有兴趣的话,可以移步:Vue如何高效通过JSX动态渲染组件
而说回这次的下拉选择,一般选项不会超过100条,毕竟多了的话,也不好选择。
当然选项多了可以考虑,支持搜索功能。
那或许这又是另外一个问题。
如今我们需要解决如何在页面中显示这几万条数据选项。
很多人也习以为常搬出了虚拟列表。
在这之前,我们先来了解一下虚拟列表。
三、虚拟列表
虚拟列表是一种优化技术,仅对可见区域进行渲染,而非可见区域的数据则不渲染或部分渲染,从而减少资源消耗,提升用户体验。这种方法特别适合长列表,性能表现优异。
实现思路:
创建一个固定高度的div,设置overflow以支持纵向滚动。计算可视区域内可以显示的数据条数,即可视区域高度除以单条数据高度。监听滚动事件,计算被卷起的数据的高度。确定区域内数据的起始索引,通过卷起高度除以单条数据高度获得。计算结束索引,即起始索引加上可显示的数据条数。提取起始和结束索引之间的数据,渲染到可视区域。设置起始索引在整个列表中的偏移位置,以更新列表内容。
不论如何滚动,只有滚动条的高度和可视区的元素内容会变化,始终保持渲染固定数量的元素,从而避免不必要的渲染开销。
对于刚接触的校友来说,可能有点小懵逼。
没关系,我们来看图。
dom元素
这是最外层的元素,设置死高度。
接着有一个元素是全部列表的数量*每一个项的高度(也就是完完整整数据的高度)
用父re子ab定位的形式,在计算top滚动了多少来定位
我计算这个高度(假如500px),每一个项50px,那一屏就加载10项
我一滚动,需要计算top和item(10项)
四、VirtualList
我们通过以上的图,大概明白了虚拟列表的实现,现在看看代码是如何实现的。
封装VirtualList组件
暴露了插槽slot,和listAll、itemHeight、contentHeight
<template>
<div :style="{ height: `${contentHeight}px` }" class="contentBox" @scroll="scroll">
<div :style="{ height: `${itemHeight * listAll.length}px`, position: 'relative' }">
<div :style="{ position: 'absolute', top: `${top}px`, width: '100%' }">
<div v-for="(item, index) in showList" :key="index" class="item">
<slot :item="item">slot>
div>
div>
div>
div>
template>
<script>
export default {
name: "list",
props: {
// 所有数据
listAll: {
type: Array,
default: () => [],
},
// 每条数据所占高度
itemHeight: {
type: Number,
default: 50,
},
//可视区域高度
contentHeight: {
type: Number,
default: 500,
},
},
data() {
return {
showList: [], //可视区域显示的数据
showNum: 0, //可是区域显示的最大条数
top: 0, //偏移量
scrollTop: 0, //卷起的高度
startIndex: 0, //可视区域第一条数据的索引
endIndex: 0, //可视区域最后一条数据后面那条数据的的索引
};
},
methods: {
getShowList() {
this.showNum = Math.ceil(this.contentHeight / this.itemHeight); //可视区域最多出现的数据条数
this.startIndex = Math.floor(this.scrollTop / this.itemHeight);
this.endIndex = this.startIndex + this.showNum;
this.showList = this.listAll.slice(this.startIndex, this.endIndex);
const offsetY = this.scrollTop - (this.scrollTop % this.itemHeight);
this.top = offsetY;
},
scroll() {
this.scrollTop = document.querySelector(".contentBox").scrollTop;
this.getShowList();
},
},
mounted() {
this.scroll();
},
};
script>
<style scoped>
.contentBox {
overflow: auto; /*内容超出高度才会出现滚动条*/
}
style>
好的,我们看看父组件使用。
"result">
<van-cell-group>
<VirtualList :listAll="list" :itemHeight="52" :contentHeight="500">
<template #default="{ item }">
<van-cell :key="item.label" :title="item.label" clickable>
<template #right-icon>
<van-radio :name="item.value" />
template>
van-cell>
template>
VirtualList>
van-cell-group>
这是可以直接使用到项目中的,放心使用。
这样子实现后:
性能提升:只渲染可见区域,显著减少DOM操作,提升渲染速度。内存节省:避免一次性加载所有数据,降低内存消耗。流畅体验:用户滚动时响应迅速,提供平滑的浏览体验。易于扩展:适用于大数据集,方便进行数据分页或无限滚动加载。
至此撒花~
后记
我们在实际项目中或多或少遇到一些奇奇怪怪的问题。
自己也会对一些写法的思考,为什么不行,又为什么行了?
最后,祝君能拿下满意的offer。
我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车
如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
小小导出,我大前端足矣!
靓仔,说一下keep-alive缓存组件后怎么更新及原理?
面试官问我watch和computed的区别以及选择?
面试官问我new Vue阶段做了什么?
前端仔,快把dist部署到Nginx上
多图详解,一次性啃懂原型链(上万字)
Vue-Cli3搭建组件库
Vue实现动态路由(和面试官吹项目亮点)
项目中你不知道的Axios骚操作(手写核心原理、兼容性)
VuePress搭建项目组件文档
原文链接
/spost/74184…