虚拟滚动列表助力性能优化

我所理解的是,虚拟滚动需要一次性获取所有数据,但是只渲染显示屏幕可见范围内的那些。

要做到这些我需要知道:

  • 一行的高度
  • 屏幕范围内能显示的行数
  • 列表在页面中距离网页顶部的位置
  • 滚动条高度

假设一次只需要展示 10 条数据,需要加载的数据是一个数组listData,只需要裁剪数据范围listData.slice(0, 10)

随着滚动条向下,将滚动条高度/一行的高度可以计算出当前行数。
而要模拟滚动条高度就要在页面挂载时就手动设置页面的高度为一行高度*listData.length
最后也是最关键的是保持列表一直保持在当前位置上,手动设置列表容器padding-top等于当前滚动条高度。

<template><ul ref="ulRef"><li v-for="(listItem, listIndex) in listData" :key="`list-${listIndex}`" :data-idx="listItem.idx"><slot :listItem="listItem"></slot></li></ul>
</template>
<script lang="ts" setup>
import { ref, computed, nextTick, reactive, watchEffect, onUnmounted } from 'vue'const props = defineProps<{listData: Array<any>
}>()// 列表HTMLElementDom
const ulRef = ref<any>(null)// 屏幕高度
const screenH = document.documentElement.clientHeightconst data = reactive<any>({// 列表第一项的高度(起始高度)initH: 0,// 一行的高度unitH: 0,// 屏幕范围内能显示个数displayCount: 10,// 列表起始值startIdx: 0
})const listData = computed(() => {let endIdx = data.startIdx + data.displayCountif (endIdx >= props.listData.length) endIdx = props.listData.lengthreturn props.listData.slice(data.startIdx, endIdx).map((v, k) => {v.idx = data.startIdx + k + 1return v})
})function scrollHandler() {// 当前滚动高度const curScrollTop = document.documentElement.scrollTopif (curScrollTop > data.initH) {const addCount = Math.floor((curScrollTop - data.initH) / data.unitH)ulRef.value.style.setProperty('padding-top', `${addCount * data.unitH}px`)data.startIdx = addCount} else {ulRef.value.style.setProperty('padding-top', '0px')data.startIdx = 0}
}watchEffect(() => {if (props.listData.length > 0) {nextTick(() => {// 列表距离顶部距离data.initH = ulRef.value.getBoundingClientRect().top + document.documentElement.scrollTop// 计算每行高度data.unitH = ulRef.value.children[0].offsetHeight// 计算屏幕内能显示的行数data.displayCount = Math.ceil(screenH / data.unitH)// 设置列表总高度 = 一行高度 * 行数const listH = data.unitH * props.listData.lengthulRef.value.style.setProperty('height', `${listH}px`)window.removeEventListener('scroll', scrollHandler)window.addEventListener('scroll', scrollHandler)})}
})onUnmounted(() => {window.removeEventListener('scroll', scrollHandler)
})
</script>

如何使用?

<template><infinite-list :listData="songs"><template #default="{ listItem }"><div>{{ listItem.title }}</div><!-- ... --></template></infinite-list>
</template>
<script lang="ts" setup>
import InfiniteList from './InfiniteList.vue'const songs = [] // 列表数据
</script>

CSS虚拟滚动

这个概念忘了在哪听到的了。其实我认为它更像是一种内容的懒加载。
他需要用到一个css属性:content-visibility:控制一个元素是否渲染其内容,它允许用户代理(浏览器)潜在地省略大量布局和渲染工作,直到需要它为止。
其值为auto时的作用是,如果该元素不在屏幕上,并且与用户无关,则不会渲染其后代元素。

假如我们有这样一段代码:

<div class="g-wrap"><div class="textarea-p">...</div>// ...<div class="textarea-p">...</div>
</div>

基于这种场景,其实我们非常希望对于仍未看到而且还未滚动到的区域,可以延迟加载,只有到我们需要展示、滚动到该处时,页面内容才进行渲染。

所以,content-visibility: auto 就应运而生了,它允许浏览器对于设置了该属性的元素进行判断,如果该元素当前不处于视口内,则不渲染该元素。

我们基于上述的代码,只需要最小化,添加这样一段代码:

.textarea-p {content-visibility: auto;
}

可以看到,在利用 content-visibility: auto 处理长文本、长列表的时候。在滚动页面的过程中,滚动条一直在抖动,这不是一个好的体验。

当然,这也是许多虚拟列表都会存在的一些问题。(当然,目前大多数人会选择“无视”它)
好在,规范制定者也发现了这个问题。这里我们可以使用另外一个 CSS 属性 —— contain-intrinsic-size来解决这个问题。

contain-intrinsic-size用来控制由 content-visibility 指定的元素的自然大小。
其实就是给需要隐藏的元素一个默认(至少是大概的)高度,让滚动条能够提前知道有这些东西。从而一开始就显示出它应该显示的大小。
比如上面的代码:

.textarea-p {content-visibility: auto;contain-intrinsic-size: 320px;
}

一些其它思考

这两天想到了一个场景:后端分页下支持删除功能的前端列表如何维持其length
针对这个问题其实去年想到了一个方案,在学姐的认可下终于试着写出来,非常简单:『滚动列表分片请求,区别于一般的“重新请求这一页甚至是回到第一页”的做法。新开一个存储。每次请求10条。后端新增一个字段给出第11-20数据。如果碰上删除,直接从前端存储里拿新的一条接上,保证了一定有10条还不用多发请求。新的请求后更新存储区』

但是这样终究觉得不够高端。高~ 端 ~
于是就在想怎么能够更流批一点。但是这又有一个问题:目前来说这个虽然很简单的方案已经完全能够解决问题。有了一丝头绪的新方案又没有想到能够支撑的真实的案例。离谱了。

虚拟滚动列表和css虚拟滚动【有思考】相关推荐

  1. 微信小程序 - 新闻动态 / 公告上下滚动列表(上下循环滚动,无限上下自动滚动列表)

    前言 本文实现了 无限上下自动滚动列表 组件,常见于新闻动态列表.公告等场景,可直接调用. 您可以自定义滚动间隔与显示多少个列表, 另外点击每项会触发事件,可用于跳转到详情页. 代码干净整洁,注释详细 ...

  2. html css字幕滚动代码,纯CSS实现滚动3D字幕

    一直以来我都想做一个滚动文本的效果,虽然有几种方法实现,其中还有使用WebGL的方法.但我还是想使用HTML和CSS来实现这样的效果. 很多年以前,在Web上实现滚动文本的动画效果一般是采用marqu ...

  3. 网页视差滚动效果html,CSS视差滚动效果

    一.效果Demo先行~视差滚动效果大家可能都听过,基本上都是JS实现的,有对应插件 - Parallax.js . 实际上,如果你对兼容性要求不是很高,比方说忽略IE浏览器,则我们使用简单的几行CSS ...

  4. html css 自动滚动代码,使用CSS自动滚动

    1.)您无法使用CSS或纯HTML启动DOM操作.你总是需要一种操纵语言(比如JavaScript) 2.)您可以通过覆盖当前CSS来删除按钮,并调整可见性或显示标记以使其脱离或(占位)不可见. 最后 ...

  5. WPF 列表虚拟化时的滚动方式

    ListBox的滚动方式 分为像素滚动和列表项滚动 通过ListBox的附加属性ScrollViewer.CanContentScroll来设置.因此ListBox的默认模板中,含有ScrollVie ...

  6. html 滚动条停止事件,CSS scroll-snap滚动事件停止及元素位置检测实现

    一.Scroll Snap是前端必备技能 CSS Scroll Snap是个非常好用的特性,可以让网页容器滚动停止的时候,无需任何JS代码的参与,浏览器可以自动平滑定位到指定元素的指定位置.类似幻灯片 ...

  7. html的li标签结合layui实现滚动列表

    在项目开发中经常遇到需要实现一个滚动列表,所以讲已经实现好的代码,提炼出来,后期遇到类似需求可以照猫画虎 代码如下 1.html页面部分 <!DOCTYPE html> <html& ...

  8. css界面内容可滚动_带有CSS滚动捕捉点的直观滚动界面

    css界面内容可滚动 Scroll Snap Points are a native CSS-only technique that you can use to create layouts whe ...

  9. css 实现滚动效果

    在做中奖列表的时候, 需要做一个名单上下滚动的效果, 纯css 效果就可以实现 <div class="marquee"> <div class="ro ...

最新文章

  1. 模拟芯片的最大“杀手”,竟然是它?!
  2. 看板管理大型项目-3.每日晨会
  3. Python自然语言处理工具
  4. openstack之neutron linuxbridge + vlan组网
  5. mysql特殊编码_Mysql 字符编码
  6. Mac下Homebrew的图形化界面工具Cakebrew
  7. f ajax event,f:ajax onevent不能使用预定义函数,但可以使用内联函数
  8. 【渝粤教育】国家开放大学2018年秋季 1167t环境水利学 参考试题
  9. android 透明变成白色,android – 状态栏不透明但是白色
  10. vim提示-bash:vim :common not found解决方法
  11. find命令使用案例
  12. Spring Boot 解决方案 - 会话
  13. Unity3D--枚举+协程控制定点移动
  14. The Willpower Instinct(自控力,意志力)
  15. LINUX修改网卡MAC地址
  16. 自动手动安装CDH5
  17. 卷积码编码器matlab,卷积码的编解码matlab仿真.doc
  18. 电商分析公式和指标整理
  19. 00后程序员摸爬滚打近一年,为学弟学妹们总结出了以下 7 条人生建议(建议收藏)
  20. 12-【istio】-【流量管理】-【流量管理原理】istio Sidecar的两种注入方式、注入原理

热门文章

  1. 网络安全意识 | 以人为本,安全意识工作大有可为
  2. torch.bmm()
  3. winedit使用教程_基础教程:BCDEDIT常用命令及使用实例(图)
  4. 《PyQT5软件开发 - 控件篇》第3章 单行文本框QLineEdit
  5. 混合现实在医学领域的应用学习日志
  6. canopen服务器协议,CANopen协议详情讲解.docx
  7. 如何在虚拟机上安装苹果系统(Mac OS)
  8. Java期末复习基础知识整理(有点长)
  9. python3 cookie_Python3标准库:http.cookies HTTP cookie
  10. android 屏幕统计,OffScreen - 屏幕时间统计