likes
comments
collection
share

客户又要一次性滚动千万条数据...

作者站长头像
站长
· 阅读数 6

欸,朋友们好,我是性能优化带师,寅时码 昨天,产品发来张截图,问我怎么这么卡 我一看,噢~原来是佐田,后端的数据,有三千多条,给我挤爆了 这时间,按照传统前端的方式,应该是 减数据、截数据、分段出

引言

像是什么 虚拟列表动态轮播图 之类的 我之前都做过了,也发过文章讲解

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


什么意思呢?

也就是仅仅加载看得见的数据,看不见的则不生成 DOM 当然,上面那句话只是最理想的状态,以目前浏览器提供的 API 来说 无缝滚动的动态加载都是障眼法,总会有一些多余的资源

回顾其他组件的实现方式

我之前做的 动态无缝轮播 组件,实际上是加载两份相同的资源实现 当需要切换时,用点障眼法就能实现 如果需要左右都能 无缝且动态 的轮播,那么就需要复制更多资源


我做的东西基本都是通用的(懒即动力),也就是说,只要你需要轮播、或者滚动 那么都可以使用,他会传递个插槽给你使用

直接放源码,我给你们省流,不会用的话看看文章末尾 gitee.com/cjl2385/dig… gitee.com/cjl2385/dig…

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

实现动态加载数据滚动

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

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

所以重点就是这个时机,你可以利用各种事件 在用户看不见的地方切换数据

这张图里,容器的大小实际上是红色的部分 接下来,我让他滚动起来,你们就能看到效果了

客户又要一次性滚动千万条数据...

很简单对吧,一个循环的动画 那么下面我变直接隐藏右边,那么就实现了

客户又要一次性滚动千万条数据...

怎么样,是不是毫无破绽 客户又要一次性滚动千万条数据...

讲解

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

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

@keyframes scrollX {
    100% {
        transform: translateX(-50%);
    }
}

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

上面说了要监听事件,那要监听什么事件呢? 显然是动画迭代完一次后的动画,每次迭代都会重新运行的事件

事件名我记得住吗?我记不住 那我是怎么写的呢?

靠猜

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

这个叫 xxx Iterateiterate是不是很眼熟 没错,就是数组的迭代器,所以我猜就是他

客户又要一次性滚动千万条数据...

那么怎么设置呢? 这里还是用老朋友,vue 的响应式 API 实现

定义一个起始索引,一个结束索引 然后用计算属性,基于他们,算出最终的数组 以后仅仅需要修改索引,大大降低开发的心智负担,大爱响应式编程

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

客户又要一次性滚动千万条数据...

此时,仅仅需要修改起始索引,即可完成 下面的函数,在动画迭代时运行即可

客户又要一次性滚动千万条数据...

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

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

源码使用说明

代码里我用到了一个设置大小的指令 v-resize 已经放在了仓库,大家在 main.ts 把指令加入即可,比如

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

依赖 在文件里从 @jl-org/tool 里导入了一个函数,大家直接下载这个包即可 是我写的工具库,不想下载的话,去 npm 找,然后复制一下 www.npmjs.com/package/@jl…

代码示例

<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>