【面试题】如何实现vue虚拟列表,纵享丝滑

news/2024/10/24 1:50:05/

大厂面试题分享 面试题库

前后端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库  web前端面试题库 VS java后端面试题库大全

前言

最近在工作中遇到了一个列表的需求,因为做的是C端,所以对性能体验要求很高,主要有下面几点要求,也可以说是痛点

  1. 就算加载上千条数据,也能够立即加载,而不会卡顿,等待时间不能太长
  2. 加载好以后用户能立马进行交互,而不是要等待,体验必须丝滑

仔细想想, 加载上千条数据,加载时间肯定会相对长一些,而又要求立即加载,这不是一个矛盾的需求么,所以如果使用常规的操作,肯定难以解决这个痛点,所以必须引出我们今天的主角才能解决今天的问题

什么是虚拟列表?

虚拟列表是一种技术,它只渲染用户当前可见的列表项,而不是渲染整个列表。

虚拟列表的原理是什么?

  1. 只渲染可视区域内的列表项,而不是渲染整个列表
  2. 当用户滚动容器时,虚拟列表会根据滚动位置和可视区域的大小计算出当前应该显示的列表项。

首先实现一个可以滑动的列表

因为我们主要讲的是虚拟列表,为了不增加大家负担,那么列表容器的高度,列表项的高度,我们都设置为已知的,而实际使用的时候,可以根据场景,动态获取

代码很简单,然后我们一次性渲染10万条数据数据

<template><div class="about"><div class="scrollView"><div class="list"><div class="item" v-for="item in list" :key="item">{{ item }}</div></div></div></div>
</template>
<script>
export default {data() {return {list: [],};},mounted() {const total = 100000;const list = [];for (let i = 0; i < total; i++) {list.push(i);}this.list = list;}
};
</script>
<style>
.scrollView {width: 200px;height: 300px;background-color: red;overflow-y: scroll;position: relative;
}.item {height: 50px;
}
</style>

测试结果非常恐怖😱,因为数据量庞大,发现才开始的时候一直卡着不动,有1s多的时间是什么也看不到的,这无疑是致命的

实现虚拟列表

列表高度为300,列表项高度为50,那么我们只需要展示6条数据就可以了,因为有可能上拉数据,那么有可能展示第7条数据,所以我们要展示7条数据,但是首次加载我们只用展示6条

所以此时我们改一下mounted生命周期

  mounted() {const total = 100000;const list = [];for (let i = 0; i < total; i++) {list.push(i);}this.data = list;this.list = list.slice(0, 6);},

问题一:我们只展示可视区域的列表,那么如何显示滚动条呢

这个问题就是一个关键,需要我们设置一个虚拟的列表,定义好高度

<template><div class="about"><div class="scrollView" @scroll="onScroll" ref="list"><!-- 虚拟列表 --><div class="virtualScroller" :style="{ height: listHeight + 'px' }"></div> <div class="list"><div class="item" v-for="item in list" :key="item">{{ item }}</div></div></div></div>
</template>
<script>
export default {data() {return {list: [],listHeight: 0,itemSize: 50,containerHeight: 300,visibleCount: 6,data: [],startOffset: 0,};},mounted() {....this.listHeight = list.length * this.itemSize;.....}
};
</script>
<style>
.list {position: absolute;top: 0;left: 0;
}
</style>

问题二:下拉列表以后,如何让列表内容显示到可视区域内

现在我们的效果是这样的,下拉的时候,列表内容都上移了

所以我们要让列表内容在滚动的时候,移动到可视区域内

我们监听scrollView的 scroll事件

<div class="scrollView" @scroll="onScroll" ref="list">

onScroll的实现包括以下几个内容

  • 滚动距离:scrollTop
  • 列表开始索引:startIndex
  • 列表结束索引:endIndex
  • 列表移动距离:startOffset: 这个是重点
this.startOffset = scrollTop - (scrollTop % this.itemSize);

所以我们的onScroll方法的实现是

onScroll() {//当前滚动位置let scrollTop = this.$refs.list.scrollTop;// 列表开始索引let startIndex = Math.floor(scrollTop / this.itemSize);// 列表结束索引let endIndex = Math.ceil((scrollTop + this.containerHeight) / this.itemSize);this.list = this.data.slice(startIndex, endIndex);// 列表移动距离this.startOffset = scrollTop - (scrollTop % this.itemSize);}

此时我们的虚拟列表就实现了

完整代码如下:

<template><div class="about"><div class="scrollView" @scroll="onScroll" ref="list"><!-- 虚拟列表 --><div class="virtualScroller" :style="{ height: listHeight + 'px' }"></div><div class="list" :style="{ transform: `translateY(${this.startOffset}px)` }"><div class="item" v-for="item in list" :key="item">{{ item }}</div></div></div></div>
</template>
<script>
export default {data() {return {list: [],listHeight: 0,itemSize: 50,containerHeight: 300,visibleCount: 6,data: [],startOffset: 0,};},mounted() {const total = 100000;const list = [];for (let i = 0; i < total; i++) {list.push(i);}this.listHeight = list.length * this.itemSize;this.data = list;this.list = list.slice(0, 6);},methods: {onScroll() {//当前滚动位置let scrollTop = this.$refs.list.scrollTop;// 列表开始索引let startIndex = Math.floor(scrollTop / this.itemSize);// 列表结束索引let endIndex = Math.ceil((scrollTop + this.containerHeight) / this.itemSize);this.list = this.data.slice(startIndex, endIndex);// 列表移动距离this.startOffset = scrollTop - (scrollTop % this.itemSize);}}
};
</script>
<style>.scrollView {width: 200px;height: 300px;background-color: red;overflow-y: scroll;position: relative;
}.item {height: 50px;
}.list {position: absolute;top: 0;left: 0;
}
</style>

那么虚拟列表和下拉加载更多有什么区别呢?

虚拟列表(Virtual List)和下拉加载更多(Infinite Scroll)都是用于优化长列表或大数据集的用户界面的技术,但它们有一些区别。

虚拟列表通过动态渲染当前可见的列表项来提高性能和内存利用率,而下拉加载更多是在用户滚动到列表底部时自动加载更多数据。两者都是为了优化大数据集或长列表的用户界面,提供更好的性能和用户体验。具体选择哪种技术取决于具体的需求和场景。

大厂面试题分享 面试题库

前后端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库  web前端面试题库 VS java后端面试题库大全


http://www.ppmy.cn/news/74148.html

相关文章

无效数据大揭秘——你不知道的那些坑!

进行数据管理时&#xff0c;无效数据可能会对生产力和决策质量造成严重的影响。如何发现和处理无效数据变得愈发重要。一起来唠唠各位大佬是如何处理的&#xff1f; ⭐ 什么是无效数据&#xff1f;⭐ 如何处理无效数据&#xff1f;⭐ 如何减少无效数据&#xff1f;⭐ 无效数据管…

Windows 环境 Rust postgress dll报错

本文将主要阐述三个bug&#xff0c;具体如下&#xff1a; 报错1&#xff1a; LNK1181: cannot open input file “libpq.lib” 命令行中输入setx PQ_LIB_DIR "C:\Program Files\PostgreSQL\14\lib" 重新 cargo build 问题解决 报错2&#xff1a;Exit code: 0xc000…

Executor 框架实现线程池,以及利用多线程读取文件

Java 中实现多线程的方式有以下几种: 1.使用 Thread 类实现多线程。 创建线程的第一种方式是继承 Java 的 Thread 并重写 run() 方法。 public class MyThread extends Thread {@Overridepublic void run() {// 线程执行的逻辑} }MyThread myThread1 = new MyThread(); myT…

计算机图形学 | 实验九:纹理贴图和天空盒

计算机图形学 | 实验九&#xff1a;纹理贴图和天空盒 计算机图形学 | 实验九&#xff1a;纹理贴图和天空盒实验概述顶点数据立方体顶点数据天空盒顶点数组 纹理载入创建纹理纹理读取纹理绑定 使用纹理立方体着色器顶点着色器片元着色器 天空盒着色器顶点着色器片元着色器 立方体…

Linux【工具 02】OpenStreetMap数据处理工具OSMCTools下载安装使用举例(osmconvert命令说明)如何获取区域边界说明

OSMCTools安装使用实例 1.Tools2.官网安装步骤3.实际安装步骤3.1 环境3.2 步骤 4.工具使用实例 OpenStreetMap的下载地址&#xff1a;Geofabrik Download Server。 OSMCTools的GitHub地址&#xff1a;https://github.com/ramunasd/osmctools Windows操作系统&#xff0c;可以…

图像比对、人像比对和人脸识别的区别是什么?

图像比对、人像比对和人脸识别都是图像处理技术&#xff0c;但是它们的实现方式和应用场景均有所不同。 图像比对 图像比对是指通过计算机视觉技术将两张或多张图片进行相似度比较。主要包括图像特征提取、匹配和评估等步骤&#xff0c;通常使用神经网络等深度学习技术来实现…

深度学习上采样下采样概念以及实现

#pic_center 400x 系列文章&#xff1a; 文章目录 参考博客概念上采样下采样 实现上采样下采样 参考博客 【深度学习】上采样&#xff0c;下采样&#xff0c;卷积 torch.nn.functional.interpolate函数 概念 上采样 简单说将图片放大&#xff0c;通过在像素键插入数据 1.…

【机器学习】 - 作业1: 基于决策树的英雄联盟游戏胜负预测

课程链接: 清华大学驭风计划 代码仓库&#xff1a;Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的&#xff0c;其分为四门课&#xff0c;包括: 机器学习(张敏教授) &#xff0c; 深度学习(胡晓林教授), 计算…