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

news2025/1/20 1:44:37

大厂面试题分享 面试题库

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

地址:前端面试题库  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.coloradmin.cn/o/556178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是接口测试?接口测试流程有哪些?我来告诉你

目录 首先&#xff0c;什么是接口呢&#xff1f; 一、常见接口&#xff1a; 二、前端和后端&#xff1a; 三、什么是接口测试&#xff1a; 四、接口组成 五、为什么要做接口测试&#xff1a; 六、接口测试怎么测&#xff1a; 七、用什么工具测 八. 接口测试持续集成 九…

chatgpt赋能Python-python_canbus

Python Canbus&#xff1a;如何使用Python编程语言控制Canbus&#xff1f; 介绍 Canbus被广泛地应用于现代汽车中&#xff0c;是一个用于通讯的协议&#xff0c;允许汽车的各个部分进行通信。为了控制Canbus&#xff0c;很多工程师都使用Python编程语言&#xff0c;因为它简单…

爬虫练习-12306自动购票升级版

文章目录 前言代码更新 前言 hello兄弟们&#xff0c;偷懒归来了。别问为啥这么久没更&#xff0c;问就是失踪了 最近一直在学习Django以及爬虫进阶之类的知识&#xff0c;加上快期末了&#xff0c;一直没有想起来自己还有一个账号没有更新&#xff0c;sorry啦 言归正传&…

SpringBoot - Jackson详解

写在前面 JSON 是目前主流的前后端数据传输方式。在 Spring Boot 项目中&#xff0c;只要添加了 WEB依赖&#xff08;spring-boot-starter-web&#xff09;&#xff0c;就可以很方便地实现 JSON 转换。WEB 依赖默认加入了 jackson-databind 作为 JSON 处理器&#xff0c;我们不…

算法小试炼(差不多相当于重新过一遍ACWING,为了夏令营做点准备)

1.最长不重复子串 这个题目的具体意思就不用我说了&#xff0c;我这里给出两种算法 1&#xff09;暴力搜索 只要机器够快&#xff0c;没有什么是暴搜解决不了的^ ^&#xff08;开玩笑 很简单&#xff0c;我们只需要遍历长度&#xff0c;跟左边界就好了&#xff0c;这个应该没…

测试必知必会的Mock数据方法

Mock数据的含义 那么Mock数据是什么意思呢 首先Mock这个英文单词有模拟的意思&#xff0c;模拟数据通俗的理解就是构造假数据&#xff0c;即Mock数据就是通过构造假数据来达到测试的目的&#xff0c;它广泛运用于功能测试、接口测试、单元测试 在功能测试中&#xff0c;可以…

离散数学 | 图论 | 欧拉图 | 哈密顿图 | 割点 | 桥(欧拉图和哈密顿图有没有割点和桥?)

本文主要解决以下几个问题&#xff1a; 1.欧拉图能不能有割点&#xff0c;能不能有桥&#xff1f; 2.哈密顿图能不能有割点&#xff0c;能不能有桥&#xff1f; 首先我们要明白几个定义 割点的定义就是在一个图G中&#xff0c;它本来是连通的&#xff0c;去掉一个点v以后这个…

【firewalld防火墙】

目录 一、firewalld概述二、firewalld 与 iptables 的区别1、firewalld 区域的概念 三、firewalld防火墙默认的9个区域四、Firewalld 网络区域1、区域介绍2、firewalld数据处理流程 五、firewalld防火墙的配置方法1、使用firewall-cmd 命令行工具。2、使用firewall-config 图形…

【计算机网络基础】章节测试4 网络层

R1与R2是一个自治系统中采用RIP路由协议的两个相邻路由器,R1的路由表如图(a)所示。如果R1收到R2发送的如图(b)所示的(V,D)报文,更新之后的R1的4个路由表项的距离从上到下依次为0、4、4、2,那么图 (b)中a、b、c、d 可能的数据一个是( C )。 A. 1、2、2、1 B. 2、2、3、1…

Java 核心技术 卷I 第2章 Java程序设计环境

第2章 Java程序设计环境 2.1 安装Java开发工具包 2.1.1 下载JDK www.oracle.com/technetwork/java/javase/downloads Java术语 2.1.2 设置JDK 下载JDK之后&#xff0c;需要安装这个开发包并明确要在哪里安装&#xff0c;后面还会需要这个信息. 指/opt/jdk1.8.0_31/bin或c…

从零开始Vue3+Element Plus后台管理系统(十四)——PDF预览和打印

其实我常常会纠结今天要写什么内容。 因为希望能够保持每日更新&#xff0c;所以要写的内容不能太难——最好是半天可以搞出demo并且输出文章&#xff0c;所以很多东西浅尝辄止&#xff0c;并没有深入研究&#xff0c;还写出了一些bug &#x1f41b; 今天又浅浅的研究了下在V…

这还只是阿里20K+测试岗面试题,看的我冷汗直流.....

朋友入职已经两周了&#xff0c;整体工作环境还是非常满意的&#xff01;所以这次特意抽空给我写出了这份面试题&#xff0c;而我把它分享给伙伴们&#xff0c;面试&入职的经验&#xff01; 大概是在3月中的时候他告诉我投递了阿里巴巴并且简历已通过&#xff0c;3月23经过…

python类型注释

目录 为什么需要类型注解 什么是类型注解 联合注解 使用注解时的注意点 为什么需要类型注解 看下图&#xff0c;很精炼&#xff1b; 什么是类型注解 Python类型注释是指在变量、函数参数、返回值等位置添加类型信息的一种语法&#xff0c;其目的是提高代码的可读性和可维护…

monkey测试方法及命令

1、查询测试包信息 # 查看已连接设备 adb devices # 带uuid查询包含test的第三方apk包 adb -s W21112003057 shell pm list package -3 | grep test # 清空logcat adb -s W21112003057 logcat -c # 启动app&#xff0c;通过日志查看安装包信息 adb -s W21112003057 logcat…

史上最全!全领域网络安全拓扑图(118页)

大家好&#xff0c;我是老杨。 前几天发了一篇OSPF的文章&#xff0c;助理发到群里和大家讨论。 好几个小友表示&#xff0c;绘制拓扑的才是最高境界&#xff0c;并且想看些拓扑图案例。 其实拓扑图案例老杨也分享过不少了。 可以看看这些往期文章&#xff0c;《超干货&…

【送书福利-第四期】从程序员到架构师:大数据量、缓存、高并发、微服务、多团队协同等核心场景实战书籍

大家好&#xff0c;我是洲洲&#xff0c;欢迎关注&#xff0c;一个爱听周杰伦的程序员。关注公众号【程序员洲洲】即可获得10G学习资料、面试笔记、大厂独家学习体系路线等…还可以加入技术交流群欢迎大家在CSDN后台私信我&#xff01; 送书福利-第四期 一、前言二、书籍介绍抽…

KY111 日期差值

1.题目&#xff1a; 2.分析&#xff1a; 1. 分别求出每一个日期与0000年0月1日距离的天数 2. 两个距离天数相减即可得到两个日期相差的天数 3.我的代码&#xff1a; #include <iostream> using namespace std;class Date { public:Date(int year 1, int month 1, …

java学习:字面量,基本语句

一、字面量 1.字面量的类型 Java字面量的类型其实跟 c 的有点相似&#xff0c;有一点不一样的就是&#xff0c;Java有个null类型&#xff0c;注意这个没有大写 2.特殊字面量 \t 是制表符&#xff0c;它的作用就是补齐一个字符串到8位&#xff0c;这样就会使输出结果变得美观…

【arxiv】关于 SAM 的论文扫读(一)

文章目录 一、阴影检测二、弱监督下的隐蔽物体分割&#xff1a;基于SAM的伪标签和多尺度特征分组三、Instruct2Act&#xff1a;利用大型语言模型将多模态指令映射到机器人动作四、OR-NeRF: Object Removing from 3D Scenes Guided by Multiview Segmentation with Neural Radia…

Lucene(5):索引维护

1 需求 管理人员通过电商系统更改图书信息&#xff0c;这时更新的是关系数据库&#xff0c;如果使用lucene搜索图书信息&#xff0c;需要在数据库表book信息变化时及时更新lucene索引库。 2 添加索引 调用 indexWriter.addDocument&#xff08;doc&#xff09;添加索引。 参…