vue-virtual-scroller的使用,展示巨量数据,长列表优化,虚拟列表

news2024/10/7 8:32:02

一、原理 

  1. 计算显示区域的高度(或宽度) 和显示区域的起始位置(scrollTop或scrollLeft)
  2. 根据每个元素的尺寸和总数目,计算出整个列表的高度(或宽度)
  3. 显示区域的高度(或宽度)和每个元素的尺寸,计算出一页能够显示的元素的数量(即动态计算了可视区域可以显示多少个元素)
  4. 根据当前显示区域的起始位置(scrollTop或scrollLeft),计算出当前显示区域应该实际显示哪些元素
  5. 根据计算出的元素列表,动态生成DOM元素并渲染到页面
  6. 当滚动时,根据当前的滚动位置,重新计算需要显示哪些元素,并根据添加或删除元素

作用: 

  • 一个虚拟滚动组件,用来处理非常长的或者无限滚动的列表。
  • 通过不渲染可视区域以外的内容,显示虚拟的滚动条来
  • 将可视区域范围内的条目渲染出来,用户滚动,会处理滚动行为(虚拟的滚动条),动态重新执行更新渲染。dom复用,不需要消耗太多资源,滚动时,cpu换内存,提升页面性能 

虚拟滚动列表实现原理解析和实战_虚拟滚动列表_03

二、vue-virtual-scroller的使用,长列表优化,虚拟列表,纵想丝滑

对于长列表数据有 10万 多条来说,我们大部分的操作都是:
1.懒加载,分页,
2.Object.freeze  冻结数组取消响应式,因为大多时候都是展示
3.高清图替换成缩略图,因为很多时候长列表的图尺寸都比较小,所以可以用小图来代替

以上能解决大部分的长列表问题,在可以分页的情况下。

但是,还有两个问题未解决,那就是:
1.不能分页的时候怎么办
2.当用户向下滑动加载了很多很多的内容时,可能是1000个10000个的时候。这个时候浏览器就会变得卡顿,特别是在手机上。原因就是因为浏览器渲染了太多的div,消耗了很多的资源(重绘和回流都是需要浏览器资源的)

所以,针对这两个问题,我们隆重的推出我们的虚拟列表,关于虚拟列表的原理,已经有很多很多的文章讲过了,本文就不再去重复了,大家可以直接去搜索一下就可以出来它的原理,大概就是只渲染缓冲区和可视区的盒子,不会去把所有列表中的盒子渲染出来,达到节省浏览器资源的目的。

另外的话,这个虚拟列表主要比较好用的组件库有 vue 中:vue-virtual-scroller 和vue-virtual-scroll-list

react的话 ,基本上就是 react-virtualized ,这个组件也非常的厉害,常用react的同学可以自己去研究下这个组件库

因为我自己是比较常用vue,下面的话,就是去教大家怎么去vue-virtual-scroller这个组件库来实现虚拟列表的

首先的话,应该去看一下官网:https://www.npmjs.com/package/vue-virtual-scroller#dynamicscroller

2.1 安装及说明 

2.1.1vue2 安装

npm i vue-virtual-scroller

然后再main.js中导入,注册使用,千万记得要把样式导入进去,之前我忘记导入样式了,找了老半天才发现

import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import VueVirtualScroller from 'vue-virtual-scroller'
Vue.use(VueVirtualScroller)

然后,你就可以愉快的去使用里面的组件了

2.1.2组件使用说明

vue-virtual-scroller 中包含这几个组件,具体都能做什么可以看官方文档,这里只介绍 RecycleScroller

  • RecycleScroller
  • DynamicScroller
  • DynamicScrollerItem

注意!!!!!: 这里需要特别注意, recycle-scroller 组件必须设置高度,自己计算也好,提前指定也好,必须设置,不然会出错。 

Props 和 Slot 说明

recycle-scroller 的接收参数说明:官方文档

prop解释
item-size元素高度,默认:null,需要设置这个高度,不然好像也会出错
items数组,列表数据源,主角
buffer加到可视区域上下的像素高度,可以适当调大,避免滚动出现的空白
key-field默认标识每行用的标识字段,默认是 id,如果你的 items 数据里没有 id,就自己想办法了,可以自己将源数据生成并添加第一行的唯一 id

 官方说明如下:

如果你指定的 keyField 存在重复的情况,就会出现列表内容缺失的情况 如下: 

 v-slot 可以为以下几个值: 官方文档

prop解释
item展示中的元素个体
index返回每个元素在 items 中的位置 inex
active元素是否处于 active 状态

案例一(基础)

好的,让我们来实现第一个虚拟列表的demo,这个demo的话,是固定了每一个item的高度的,并且也是一次性就去加载数据的,不会有上拉加载数据的操作。也就是说,如果你要渲染的list就是这么多,并且高度一致的话,就可以用这个去改

代码:

<template>
    <div class="home">
        <!-- <div class="father">
      <div class="right">
        <div class="every_type">
          <div class="item_box">
            <div
              class="item"
              v-for="(item, index) in items"
              :key="index"
            >
              {{ item.title }}
            </div>
          </div>
          
        </div>
      </div>
    </div> -->
    <h3>vue-virtual-scroller的使用,展示巨量数据,长列表优化,虚拟列表</h3>
    <h3>recycle-scroller 组件必须设置高度,自己计算也好,提前指定也好,必须设置,不然会出错。</h3>
      <RecycleScroller
        class="scroller"
        :items="items"
        :item-size="50"
        v-if="items.length"
      >
        <template v-slot="{ item }">
          <div class="user">
            {{ item.title }}--- <h4>{{ item.id }}</h4>
          </div>
        </template>
      </RecycleScroller>
    </div>
  </template>
  
  <script>
  export default {
    name: 'Home',
    components: {},
    data () {
      return {
        items: []
      }
    },
    created () {
      this.getData()
      // console.log(this.items)
    },
    methods: {
      getData () {
        for (let i = 0; i < 200000; i++) {
          this.items.push({ title: 'muzidigbig' ,id : i})
        }
      }
    }
  }
  </script>
  
  <style lang="less" scoped>
  .scroller {
    height: 300px;
    background-color: rgba(0, 0, 0, 0.1);
  }
  
  .user {
    height: 50px;
    padding: 0 12px;
    display: flex;
    align-items: center;
  }
  </style>
  
  

使用起来非常的简单,像这种只需要使用到RecycleScroller就行了,:items="items"设置的是对应的数组,:item-size="50"设置的是每个item的高度。另外需要注意的就是下面的那两个样式记得要复制到位,因为虚拟列表要求你的scroller和user是要有高度的

列表元素的高度设置注意事项
最好呢, prop 中的 itemSize 跟列表模板的高度一致。
比如上面代码中的例子, .user 的 css 高度最好设置成 prop 中 item-size 一致的高度 50px,如果有 padding 那就另算。

怎么判断我们的虚拟列表使用成功了呢?可以打开F12的element来看,当我们滚动滚动条,但是盒子不增加,只做位移操作的话,就可以判断我们的虚拟列表使用成功了。如果没有使用的虚拟列表的话,那里的item盒子应该是20w个

 另外的话,我的代码里面还有一段注释,就是没有使用虚拟列表时去渲染20w个div时,大家可以打开注释来看一下,哪个时间花的比较多。其实我已经测过了,虚拟列表花的时间短多了!

案例二 (定高,上拉加载)

已经知道了基本的使用,那么我们就可以加深一点,看一下,如果一次不加载这么多,只加载5个数据,然后上拉触底的时候再去加载,这种应该如何去实现。(这种还是高度一定,但是可以上拉加载了)

<template>
  <div>
    <RecycleScroller
      class="scroller"
      :items="items"
      :item-size="300"
      :emitUpdate="true"
      @update="update"
      @resize="resize"
      @visible="visible"
      @hidden="hidden"
      @scroll="scroll"
      v-if="items.length"
    >
      <template slot-scope="props">
        <li :key="props.itemKey">
          <div>{{ props.item.title }}</div>
          <img :src="props.item.img" alt="" />
        </li>
      </template>
    </RecycleScroller>
  </div>
</template>
<script>
export default {
  name: 'test',
  data () {
    return {
      items: []
    }
  },
  created () {
    this.getData()
  },
  mounted () {},
  methods: {
    getData () {
      this.$axios('/home/swiper').then(res => {
        console.log(res)
        this.items = res.data.data.list
      })
    },
    scroll () {
      console.log(111)
    },
    update (start, end) {
      // console.log(start, end)
      if (end === this.items.length) {
        console.log(1111)
        let temp = []
        // temp.push({
        //   id: 101,
        //   img: '"http://dummyimage.com/200x100/FF6600"',
        //   time: '2003-02-02',
        //   title: 'hahahha'
        // })
        this.$axios('/home/add').then(res => {
          // console.log(res)
          // this.items = res.data.data.list
          temp = [...this.items, ...res.data.data.list]
          // console.log(temp)
          this.items = temp
        })
        // this.items = temp
      }
    },
    resize () {
      console.log('resize')
    },
    visible () {
      console.log('visible')
    },
    hidden () {
      console.log('hidden')
    }
  }
}
</script>
<style lang="css" scoped>
.scroller {
  height: 300px;
  background-color: #ccc;
}

.user {
  height: 32%;
  padding: 0 12px;
  display: flex;
  align-items: center;
}
</style>

这段代码里面稍微比刚才的复杂了一点点,其实就是加了 :emitUpdate=“true” 和 @update=“update”。其实最重要的是这个update方法,那为什么需要:emitUpdate="true"呢,是因为人家官网说了:要想触发这个update事件,就必须去设置emitUpdate为true。

在这个update方法中,我们就只做了一件事,就是当我们的结束的index等于我们的数组长度的时候,我们就去请求接口来获取新的数据,然后加入到数组中就行了

案例三(不定高,上拉加载) 

最后,肯定还有朋友遇到的是不定高度的盒子,并且还需要进行上拉加载

果真产品思想不滑坡,困难总比方法多!

上代码:

<template>
  <div>
    <DynamicScroller
      :items="items"
      :min-item-size="54"
      class="scroller"
      :emitUpdate="true"
      @update="update"
      @resize="resize"
      @visible="visible"
      @hidden="hidden"
      @scroll="scroll"
      v-if="items.length"
    >
      <template v-slot="{ item, index, active }">
        <DynamicScrollerItem
          :item="item"
          :active="active"
          :size-dependencies="[item.message]"
          :data-index="index"
        >
          <li class="single-item" :key="item.id">
            <div class="left-pic"><img :src="item.img" alt="" /></div>
            <div class="right-info">
              <span>标题:{{ item.title }}</span>
              <span>项目数量:{{ item.id }}</span>
              <span>项目时间:{{ item.time }}</span>
              <span>项目描述:{{ item.des }}</span>
            </div>
          </li>
        </DynamicScrollerItem>
      </template>
    </DynamicScroller>
  </div>
</template>
<script>
export default {
  name: 'test',
  data () {
    return {
      items: []
    }
  },
  created () {
    this.getData()
  },
  mounted () {},
  methods: {
    getData () {
      this.$axios('/home/swiper').then(res => {
        console.log(res)
        this.items = res.data.data.list
      })
    },
    scroll () {
      console.log(111)
    },
    update (start, end) {
      if (end === this.items.length) {
        console.log(1111)
        let temp = []
        this.$axios('/home/add').then(res => {
          temp = [...this.items, ...res.data.data.list]
          this.items = temp
        })
      }
    },
    resize () {
      console.log('resize')
    },
    visible () {
      console.log('visible')
    },
    hidden () {
      console.log('hidden')
    }
  }
}
</script>
<style lang="less" scoped>
.scroller {
  height: 300px;
  background-color: #ccc;
}

.user {
  height: 32%;
  padding: 0 12px;
  display: flex;
}
.single-item {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  border-bottom: 1px solid rgb(187, 167, 167);
  .left-pic {
    width: 200px;
    img {
      width: 200px;
    }
  }
  .right-info {
    padding-left: 20px;
    text-align: left;
    span {
      display: block;
      &:last-child {
        word-break: break-all;
      }
    }
  }
}
</style>

这次使用的组件就是DynamicScroller和DynamicScrollerItem,因为第一个组件RecycleScroller官网也说了,只能用于固定高度的情况下。

这一块的话,其实最主要的就是替换了组件。删除了传入固定高度的代码。

三、vue3 使用 vue-virtual-scroller 

安装

npm i vue-virtual-scroller@next

安装完后 package.js 中会多出

 "vue-virtual-scroller": "^2.0.0-alpha.1"

main.js

import "vue-virtual-scroller/dist/vue-virtual-scroller.css" // 引入它的 css
import VueVirtualScroller from "vue-virtual-scroller" // 引入
app.use(VueVirtualScroller) // use 

四、无缝滚动 vue-seamless-scroll 滚动表格

https://blog.51cto.com/u_12881709/5959345 

五、结语

所有的操作都在官方 API 文档中有,我只是摘取了部分,哪里不太明白的话可以去看原文档。

GitHub - Akryum/vue-virtual-scroller: ⚡️ Blazing fast scrolling for any amount of data

 例子源码:

五笔码表助手

可以查看在线例子:

码表助手
VUE2 + ELEMENT 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/841434.html

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

相关文章

netty面试题2

1、一次完整的HTTP请求的所经历的步骤 1、首先进行DNS域名解析&#xff08;本地浏览器缓存、操作系统缓存或者DNS服务器&#xff09;&#xff0c;首先会搜索浏览器自身的DNS缓存&#xff08;缓存时间比较短&#xff0c;大概只有1分钟&#xff0c;且只能容纳1000条缓存&#xff…

STM32单片机蓝牙APP宠物自动喂食器定时语音提醒喂食系统设计

实践制作DIY- GC00162---蓝牙APP宠物自动喂食器 一、功能说明&#xff1a; 基于STM32单片机设计---蓝牙APP宠物自动喂食器 二、功能说明&#xff1a; STM32F103C系列最小系统板LCD1602显示器DS1302时钟模块5个按键语音播报模块ULN2003步进电机模块LED灯板HC-05蓝牙模块&#x…

了解Linux 的 mmap --- 笔记

学习这篇博客&#xff0c;进行了一些归纳Linux下mmap_linux mmap_一个山里的少年的博客-CSDN博客https://blog.csdn.net/qq_56999918/article/details/127070280 >>读取文件 读取文件方法&#xff1a;由操作系统提供的两个方法&#xff0c;read和write来读写文件。 由…

eNSP:mgre与ospf的优化综合实验

实验要求&#xff1a; 第一步&#xff1a;路由器、IP的配置 r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int g 0/0/0 [r1-GigabitEthernet0/0/0]ip add 172.16.1.1 20 [r1-GigabitEthernet0/0/0]int lo0 [r1-LoopBack0]ip a…

C#,数值计算——堆选择(Heap Select)的计算方法与源程序

1 简述 HeapSelect 是一种用于选择数组中第 K 个最大元素的算法。它是选择问题的变体&#xff0c;涉及在无序或偏序集合中查找特定元素。 算法概要&#xff1a;数组被转换为最大堆&#xff0c;然后反复删除根节点并替换为下一个最大的元素&#xff0c;直到找到第 K 个最大的元…

2023《财富》500强|500强中超过10%已是盖雅客户,100强中已合作超过1/4

7月11日 &#xff0c;财富中文网发布了 &#xff0c;该榜单覆盖范围包括在中国境内外上市的所有中国公司&#xff0c;根据全球范围内最大的中国上市企业过去一年的业绩和成就进行排名。因此&#xff0c;上榜的上市公司不仅是经营规模大&#xff0c;绝大多数也是各自行业的龙头…

【LeetCode】240.搜索二维矩阵Ⅱ

题目 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,…

【无标题】云原生在工业互联网的落地及好处!

什么是工业互联网&#xff1f; 工业互联网&#xff08;Industrial Internet&#xff09;是新一代信息通信技术与工业经济深度融合的新型基础设施、应用模式和工业生态&#xff0c;通过对人、机、物、系统等的全面连接&#xff0c;构建起覆盖全产业链、全价值链的全新制造和服务…

软件测试工程师的基础必备技能:功能测试解读

什么是功能测试&#xff1f; 根据百科的官方定义&#xff1a;功能测试就是对产品的各功能进行验证&#xff0c;根据功能 测试用例&#xff0c;逐项测试&#xff0c;检查产品是否达到用户要求的功能。 通俗的解读&#xff1a; 功能测试&#xff0c;也叫行为测试&#xff0c;即测…

【mysql】实现递归查询

mysql实现递归查询的方法&#xff1a;首先创建表&#xff0c;并初始化数据&#xff1b;然后向下递归&#xff0c;利用find_in_set()函数和group_concat()函数、with recursive实现递归查询。 mysql实现递归查询的方法&#xff1a; 1、创建表 DROP TABLE IF EXISTS t_areainf…

微信小程序分享实现拉新绑定(用户关系绑定)

分享人此时已经是登陆状态&#xff0c;所以在分享的时候直接从本地存储中拿到用户的userId并拼接到分享链接上&#xff0c;其他用户在点击链接打开详情页之后会判断当前链接参数中有无uid有的话则直接存入本地中用作新用户登录注册时候请求接口的判断&#xff0c;最后在砍价记录…

win10 2022unity设置中文

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言解决方法 前言 在Edit->preferences里找不到language选项。 解决方法 【1】打开下面地址 注意 :把{version}换成你当前安装的版本&#xff0c;比如说如果…

Hive创建外部表详细步骤

① 在hive中执行HDFS命令&#xff1a;创建/data目录 hive命令终端输入&#xff1a; hive> dfs -mkdir -p /data; 或者在linux命令终端输入&#xff1a; hdfs dfs -mkdir -p /data; ② 在hive中执行HDFS命令&#xff1a;上传/emp.txt至HDFS的data目录下&#xff0c;并命名为…

高德地图实现点聚合功能的详细步骤

目录 介绍准备工作1.注册并登录高德地图开放平台&#xff0c;申请密钥2.在Vue项目中安装高德地图的相关库/插件。 一、点聚合1.引入高德地图API<font color purple>initializeMap()<font color purple>loadData()<font color purple>createMarkerClustere…

4 三组例子,用OpenCV玩转图像-AI-python

读取&#xff0c;缩放&#xff0c;旋转&#xff0c;写入图像 首先导入包&#xff0c;为了显示导入matplotlib/为了在matplotlib显示 导入CV2/查看版本 导入图片/查看图片类型 图片数组 数组大小 对于opencv通道顺序蓝色B、绿色G、红色R matplotlib通道顺序为 红色R、绿色G、蓝…

前端架构师岗位的工作职责(合集)

前端架构师岗位的工作职责1 职责&#xff1a; 1.制定前端的标准和规范&#xff0c;并推广和应用&#xff0c;提高团队的开发效率; 2.前端架构的框架或核心模块的设计与实现; 3.在前端架构、设计与开发上对团队进行足够的指导; 4.在日常的系统设计与优化上与服务端团队紧密合…

深度学习基础知识扫盲

深度学习 监督学习&#xff08;Supervised learning&#xff09;监督学习分类 无监督学习&#xff08;Non-supervised learning&#xff09;无监督学习的算法无监督学习使用场景 术语特征值特征向量特征工程&#xff08;Feature engineering&#xff09;特征缩放Sigmod functio…

【果树农药喷洒机器人】Part2:机器人变量喷药系统硬件选型

本专栏介绍&#xff1a;付费专栏&#xff0c;持续更新机器人实战项目&#xff0c;欢迎各位订阅关注。 关注我&#xff0c;带你了解更多关于机器人、嵌入式、人工智能等方面的优质文章&#xff01; 文章目录 一、引言二、变量喷药系统总体要求2.1系统功能要求2.2系统技术要求 三…

怎样能做成小米左侧边栏效果

1、现在我想做成小米左侧边栏这样的效果&#xff0c;该怎么做呢&#xff1f; 2、小米商城触碰之后会显示出新的商品案例 3、一碰到之后会出现这个列表 4、这里涉及到了元素显示模式&#xff1a; 5、用人进行划分可以分为男人和女人&#xff0c;根据男人和女人的特性进行相应的…

JJWT快速入门

本篇介绍使用 JJWT&#xff08;Java JWT&#xff09;库来生成 JWT Token&#xff0c;步骤如下&#xff1a; 添加依赖&#xff1a; 在项目中添加 JJWT 依赖项。对于 Maven 项目&#xff0c;可以在 pom.xml 文件中添加以下依赖项&#xff1a; <dependency><groupId>…