客户又要一次性滚动千万条数据 引言 回顾其他组件的实现

欸,朋友们好,我是性能优化带师,寅时码

昨天,产品发来张截图,问我怎么这么卡

我一看,噢~原来是佐田,后端的数据,有三千多条,给我挤爆了

这时间,按照传统前端的方式,应该是 减数据、截数据、分段出

引言

像是什么 虚拟列表动态轮播图 之类的

我之前都做过了,也发过文章讲解

这次又需要做一个 动态加载的自动滚动组件


什么意思呢?

也就是仅仅加载看得见的数据,看不见的则不生成 DOM

当然,上面那句话只是最理想的状态,以目前浏览器提供的 API 来说

无缝滚动的动态加载都是障眼法,总会有一些多余的资源

回顾其他组件的实现方式

我之前做的 动态无缝轮播 组件,实际上是加载两份相同的资源实现

当需要切换时,用点障眼法就能实现

如果需要左右都能 无缝且动态 的轮播,那么就需要复制更多资源


我做的东西基本都是通用的(懒即动力),也就是说,只要你需要轮播、或者滚动

那么都可以使用,他会传递个插槽给你使用

动态无缝轮播图实现,含源码

直接放源码,我给你们省流,不会用的话看看文章末尾

gitee.com/cjl2385/dig…

gitee.com/cjl2385/dig…

看我这么体贴的份上,别光收藏,点点赞呀

实现动态加载数据滚动

这里就讲点技巧吧,我实现动态加载

只有两点

  1. 两份数据,一份隐藏
  2. 找准时机,偷偷摸摸的切换数据,让人看不出来

所以重点就是这个时机,你可以利用各种事件

在用户看不见的地方切换数据

这张图里,容器的大小实际上是红色的部分

接下来,我让他滚动起来,你们就能看到效果了

image.png
很简单对吧,一个循环的动画

那么下面我变直接隐藏右边,那么就实现了

demo1.gif
怎么样,是不是毫无破绽

demo3.gif

讲解

  1. 准备一个数组,让他的长度,设置为用户长度的两倍
  2. 容器设置溢出隐藏,所以这时能看见的,又变成了用户指定的大小
  3. 设置一个动画,动画执行仅仅到 50% 就够了
  4. 动画设置成无限循环
  5. 监听动画的某个事件,改变数组的数据

动画如下,我写的组件比较通用,所以方向也能设置

1
2
3
4
5
6
7
8
9
10
11
css复制代码@keyframes scrollX {
100% {
transform: translateX(-50%);
}
}

@keyframes scrollY {
100% {
transform: translateY(-50%);
}
}

上面说了要监听事件,那要监听什么事件呢?

显然是动画迭代完一次后的动画,每次迭代都会重新运行的事件

事件名我记得住吗?我记不住

那我是怎么写的呢?

靠猜

输入一点前缀,使用快捷键呼出代码提示,然后一个个看呗

我写的快捷键大全指南

这个叫 xxx Iterateiterate是不是很眼熟

没错,就是数组的迭代器,所以我猜就是他

image.png
那么怎么设置呢?

这里还是用老朋友,vue 的响应式 API 实现

定义一个起始索引,一个结束索引

然后用计算属性,基于他们,算出最终的数组

以后仅仅需要修改索引,大大降低开发的心智负担,大爱响应式编程

这里的 showCount 就是展示的长度,上面说了要设置成两倍

image.png
此时,仅仅需要修改起始索引,即可完成

下面的函数,在动画迭代时运行即可

image.png

这样的话,就算有上千万条数据,也仅仅会展示容器大小 * 2 的长度

还有一些简单的细节,比如鼠标移入暂停动画什么的我就不讲了

源码里已经写了

源码使用说明

代码里我用到了一个设置大小的指令 v-resize

已经放在了仓库,大家在 main.ts 把指令加入即可,比如

1
ts复制代码app.directive('resize', { ... }) // 或者使用 app.use,前提是要写成插件提供 install 方法

依赖

在文件里从 @jl-org/tool 里导入了一个函数,大家直接下载这个包即可

是我写的工具库,不想下载的话,去 npm 找,然后复制一下

www.npmjs.com/package/@jl…

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
vue复制代码<VirtualScroll :data="data"
style="width: 400px;"
:speed="120"
:item-size="100">
<template v-slot="{ item }">
<div class="item">{{ item.data }}</div>
</template>
</VirtualScroll>

<script setup lang="ts">
const data = ref(Array.from({ length: 99999 }, (_, i) => ({ data: i + 1 })))
</script>

<style>
.item {
font-size: 30px;
background-color: lightblue;
border: 1px solid;
height: 100%;
width: 100%;
}
</style>

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%