在工作中,有时会遇到需要一些不能使用分页方式来加载列表数据的业务情况,对于此,我们称这种列表叫做长列表。比如,在一些外汇交易系统中,前端会实时的展示用户的持仓情况(收益、亏损、手数等),此时对于用户的持仓列表一般是不能分页的。

那么我们应该怎么操作才能够提高浏览器渲染的性能呢?下面是一种具体的做法,引用的是云中桥的文章高性能渲染十万条数据。

  • 什么是虚拟列表

虚拟列表其实是按需显示的一种实现,即只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能。
假设有1万条记录需要同时渲染,我们屏幕的可见区域的高度为500px,而列表项的高度为50px,则此时我们在屏幕中最多只能看到10个列表项,那么在首次渲染的时候,我们只需加载10条即可。

说完首次加载,再分析一下当滚动发生时,我们可以通过计算当前滚动值得知此时在屏幕可见区域应该显示的列表项。

假设滚动发生,滚动条距顶部的位置为150px,则我们可得知在可见区域内的列表项为第4项至`第13项。

实现
虚拟列表的实现,实际上就是在首屏加载的时候,只加载可视区域内需要的列表项,当滚动发生时,动态通过计算获得可视区域内的列表项,并将非可视区域内存在的列表项删除。

  • 计算当前可视区域起始数据索引(startIndex)
  • 计算当前可视区域结束数据索引(endIndex)
  • 计算当前可视区域的数据,并渲染到页面中
  • 计算startIndex对应的数据在整个列表中的偏移位置startOffset并设置到列表上

由于只是对可视区域内的列表项进行渲染,所以为了保持列表容器的高度并可正常的触发滚动,将Html结构设计成如下结构:

<div class="infinite-list-container"><div class="infinite-list-phantom"></div><div class="infinite-list"><!-- item-1 --> <!-- 你要进行v-for的地方><!-- item-2 --><!-- ...... --><!-- item-n --></div>
</div>

infinite-list-container 为可视区域的容器
infinite-list-phantom 为容器内的占位,高度为总列表高度,用于形成滚动条
infinite-list 为列表项的渲染区域

接着,监听infinite-list-containerscroll事件,获取滚动位置scrollTop

假定可视区域高度固定,称之为screenHeight
假定列表每项高度固定,称之为itemSize
假定列表数据称之为listData
假定当前滚动位置称之为scrollTop

则可推算出:

  • 列表总高度listHeight = listData.length * itemSize
  • 可显示的列表项数visibleCount = Math.ceil(screenHeight / itemSize)
  • 数据的起始索引startIndex = Math.floor(scrollTop / itemSize)
  • 数据的结束索引endIndex = startIndex + visibleCount
  • 列表显示数据为visibleData = listData.slice(startIndex,endIndex)

当滚动后,由于渲染区域相对于可视区域已经发生了偏移,此时我需要获取一个偏移量startOffset,通过样式控制将渲染区域偏移至可视区域中。

  • 偏移量startOffset = scrollTop - (scrollTop % itemSize);

好了准备工作介绍完毕,现在开始封装组件,下面是封装的代码。

<template><div ref="list" class="infinite-list-container" @scroll="scrollEvent($event)"><div class="infinite-list-phantom" :style="{ height: listHeight + 'px' }"></div><div class="infinite-list" :style="{ transform: getTransform }"><div ref="items"class="infinite-list-item" v-for="item in visibleData" :key="item.id":style="{ height: itemSize + 'px',lineHeight: itemSize + 'px' }">{{ item.value }}</div></div></div>
</template><script>
export default {name:'VirtualList',props: {//所有列表数据listData:{type:Array,default:()=>[]},//每项高度itemSize: {type: Number,default:200}},computed:{//列表总高度listHeight(){return this.listData.length * this.itemSize;},//可显示的列表项数visibleCount(){return Math.ceil(this.screenHeight / this.itemSize)},//偏移量对应的stylegetTransform(){return `translate3d(0,${this.startOffset}px,0)`;},//获取真实显示列表数据visibleData(){return this.listData.slice(this.start, Math.min(this.end,this.listData.length));}},mounted() {this.screenHeight = //this.$el.clientHeight;  这里修改为你那个列表可视的高度this.start = 0;this.end = this.start + this.visibleCount;},data() {return {//可视区域高度screenHeight:0,//偏移量startOffset:0,//起始索引start:0,//结束索引end:null,};},methods: {scrollEvent() {//当前滚动位置let scrollTop = this.$refs.list.scrollTop;//此时的开始索引this.start = Math.floor(scrollTop / this.itemSize);//此时的结束索引this.end = this.start + this.visibleCount;//此时的偏移量this.startOffset = scrollTop - (scrollTop % this.itemSize);}}
};
</script><style scoped>
.infinite-list-container {height: 100%;overflow: auto;position: relative;-webkit-overflow-scrolling: touch;
}.infinite-list-phantom {position: absolute;left: 0;top: 0;right: 0;z-index: -1;
}.infinite-list {left: 0;right: 0;top: 0;position: absolute;text-align: center;
}.infinite-list-item {padding: 10px;color: #555;box-sizing: border-box;border-bottom: 1px solid #999;
}
</style>

listDataitemSize分别是你想传入的数据、每一项数据的高度,.infinite-list-container要记得设置高度(不一定是100%,也可以是你想要设置px的高度),.infinite-list-item可以设置为你想要的样式,其他样式要保持一致。

demo在这里https://codesandbox.io/s/virtuallist-1-rp8pi

好了,以上就是固定宽高渲染十万条数据的方法,不固定宽高的可以看看上面那个作者的文章。

--------------------------------------------------------------------下面介绍如下增加一个搜索框搜索这些数据

2020年4月3日新增搜索关键词高亮功能

<input type="text" v-model="search">data:{return{search:''
}
}
//只需要修改一下computed和添加watch
computed:{replaceArr () {const listData = JSON.parse(JSON.stringify(this.listData))const search= this.search// 匹配关键字正则const replaceReg = new RegExp(search, 'g')// 高亮替换v-html值const replaceString = `<font color='#F14F4A'>${search}</font>`for (let i = 0; i < listData.length; i++) {// 开始替换listData [i]= listData [i].replace(replaceReg, replaceString)}return listData }_listData(){return this.replaceArr.filter(data => {return Object.keys(data).some(key => {return (String(data[key]).toLowerCase().indexOf(this.search) > -1)})})},//列表总高度listHeight(){return this._listData.length * this.itemSize;},//可显示的列表项数visibleCount(){return Math.ceil(this.screenHeight / this.itemSize)},//偏移量对应的stylegetTransform(){return `translate3d(0,${this.startOffset}px,0)`;},//获取真实显示列表数据 + 模糊搜索visibleData(){return this._listData.slice(this.start, Math.min(this.end,this._listData.length));}},watch: {search() {this.$refs.list.scrollTop = 0}},

现在就可以实现搜索这些数据了。

在vue中如何高性能渲染十万条数据(虚拟列表)并且增加个搜索框可以搜索到这些数据相关推荐

  1. mysql虚拟列表_「前端进阶」高性能渲染十万条数据(虚拟列表)

    前言 在工作中,有时会遇到需要一些不能使用分页方式来加载列表数据的业务情况,对于此,我们称这种列表叫做长列表.比如,在一些外汇交易系统中,前端会实时的展示用户的持仓情况(收益.亏损.手数等),此时对于 ...

  2. vue中 给v-for渲染的元素动态添加移除类名

    vue中 给v-for渲染的元素动态添加移除类名 今天在项目中需要做一个效果,点击对应的li改变当前的color,其他的li取消颜色,在jQuery中这很容易,由于之前已经引入了jQuery,所以直接 ...

  3. Vue中v-html无法渲染

    vue 中v-html将原始html渲染为带样式的文本 最近在使用v-html去渲染富文本的时候发现,怎么都渲染不出. 后发现后端为了安全性考虑,将<".">" ...

  4. list vue 添加数据方法_vue ajax获取数据填充列表,增加,删除

    Document 添加品牌 Name: IdNameCtimeOperation {{item.id}}{{item.name}}{{item.ctime}} 删除 // 如果我们通过全局配置了,请求 ...

  5. vue 父页面中的方法 调用_解决Vue中页面成功渲染数据undefined的问题

    前言 这个标题不太好取. 本文需要下面的知识: https://zhuanlan.zhihu.com/p/260811233​zhuanlan.zhihu.com 问题描述 我最近的一个功能需求是通过 ...

  6. php 拖拽 上传文件 进度,在Vue中如何实现带进度条的文件拖动上传功能

    这篇文章主要介绍了Vue实现带进度条的文件拖动上传功能,本文通过实例代码给大家介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下 1. 基本界面 content="width=devic ...

  7. 在vue中使用mathjax渲染latex数学公式

    第一步 在public index.js中引入 mathjax <script type="text/javascript" async src="https:// ...

  8. 微信小程序 使用.wxs在.wxml中分割字符串渲染多条数据

    在开发微信小程序的项目中,由于接口中有一个字段的值以符号作为分隔,存放了多个value需要在前端展示(例如下图中的good_field字段). 需求效果图 首先这是一个循环渲染出来列表,我无法在这整个 ...

  9. vue数据改变渲染问题_解决Vue中页面成功渲染数据undefined的问题

    前言 这个标题不太好取. 本文需要下面的知识:https://zhuanlan.zhihu.com/p/260811233​zhuanlan.zhihu.com 问题描述 我最近的一个功能需求是通过a ...

最新文章

  1. malloc为什么会报错:memory corruption
  2. python open
  3. centos mysql php tomcat_centos 一键部署安装nginx,mysql,php,apache,tomcat,redis等包合集
  4. broken pipe怎么解决 数据太大_振动筛噪音太大、扬尘问题严重,不够环保怎么办?看看这篇文章,帮您解决困扰...
  5. 如何搭建基于C#和 Appium 的 Android自动测试环境
  6. 荣耀赵明评苹果发布会掉队5G:意料之中 情理之外
  7. ajax 2分钟超时_ajax和axios、fetch的区别
  8. 中文版边缘计算白皮书发布,引领行业新趋势
  9. msvcr71.dll丢失的解决方法,如何快速进行丢失修复?
  10. imap接收邮件服务器,配置 Outlook 从 IMAP 服务器接收邮件
  11. 【除夕】春晚,我只要红包(内附节目单)
  12. error C2144: syntax error: 'int' should be preceded by ';'
  13. Spring微服务实战第2章 使用Spring Boot构建微服务
  14. FPGA原理和结构简介
  15. Java面向对象案例——购物车
  16. 有限状态机(FSM)设计原理
  17. 百度地图API之获取真实轨迹
  18. 结构体 位段 枚举 联合体
  19. 服务器系统电源管理,企业IT节能 巧用Windows系统电源管理
  20. js获取控制浏览器,屏幕,对象宽度和高度,文件大小

热门文章

  1. 茄子科技(海外SHAREit Group)赋能出海APP加速布局新兴市场
  2. 北京医院不开刀祛雀斑的方法
  3. amd同步多线程_首次同步多线程!AMD第三代锐龙3 3300X/3100上市:4核心8线程、PCIe 4加持...
  4. 创维linux怎么连接wifi,不同品牌智能电视连接蓝牙设备的方法合集!当贝市场精心整理...
  5. jinja2学习总结
  6. Verdi UVM Debug Mode 简单使用
  7. linux中umask的原理和作用,Linux 的umask详解
  8. Python中的网络通信
  9. 20172266遥感一班李安娜第四次笔记
  10. 智能体脂称方案的实现