网站域名备案更改吗,建设电影网站怎么上传电影,仿58网站怎么做,网站免费做招生宣传定高虚拟列表
基本认识
在数据如潮水般涌来的今天#xff0c;如何高效地展示和管理这些数据成为了开发者们面临的一大挑战#xff0c;传统的列表渲染方式在处理大量数据时#xff0c;往往会导致页面卡顿、滚动不流畅等问题#xff0c;严重影响用户体验#xff08;在页面…定高虚拟列表
基本认识
在数据如潮水般涌来的今天如何高效地展示和管理这些数据成为了开发者们面临的一大挑战传统的列表渲染方式在处理大量数据时往往会导致页面卡顿、滚动不流畅等问题严重影响用户体验在页面渲染大量的 dom 时不仅是在第一次渲染比较影响性能外在后续的每一次回流或重绘时也会造成巨大的性能的问题 - 我们需要知道 JS 执行永远要比 DOM 快的多
然而有一种技术能够在不牺牲用户体验的前提下显著提升大数据集的处理效率它就是——虚拟列表
虚拟列表 实际上是一种实现方案只对 可视区域 进行渲染对 非可视区域 中的区域不渲染或只渲染一部分渲染的部分叫 缓冲区不渲染的部分叫 虚拟区从而达到极高的性能
虚拟列表也分为定高虚拟列表与非定高虚拟列表等定高虚拟列表的意思就就是说列表中每一项的高度需要是一样的反之不定高就是列表中的每一项高度都是不缺订单 - 我们这里先来学一下定高虚拟列表的实现方式后续再继续更新不定高虚拟列表的实现方式
我们可以先通过一张图来简单分析定高虚拟列表 从图中可以看出我们可以将列表分为三个区域可视区、缓冲区、虚拟区 而我们主要针对 可视区 和 缓冲取 进行渲染
基本实现
这里采用 vue3 来实现如果使用其它框架的或原生对应实现思路基本也是差不多的
HTML 页面布局 容器元素 - 我们需要有一个可视窗口的容器可以是一整个屏幕视口也可以通过指定对应容器 .virtual-list-container 的高度并使该元素作为可视区域 占位区域 - 在容器中我们还需要一个占位元素用于撑开容器的高度使其容器可以存在对应的滚动条因为容器中只渲染可视区域中的元素所以我们还需要该占位元素来根据列表的数据量来撑出对应滚动条的高度 内容区域 - 最后我们还需要有一个可视区域的容器这块部分为真正用户看到的列表区域对应渲染的数据实际上是 可视区域 加 缓存区域 的列表数据 → tip: 缓冲区的作用是防止快速下滑或者上滑的过程中出现空白区域 !-- 容器元素 --
div classvirtual-list-container!-- 占位元素 --div classvirtual-list-placeholder/div!-- 渲染区域 --div classvirtual-list-content!-- 子组件: 列表中的每一项 --/div
/divtip: 这里只是一个简单的结构因为后续还有需要在这些结构中进行一些动态的修改在 JS 中我们需要的状态 list - 列表数据所有数据 showList - 所要真正展示的数据在所有数据列表 list 中进行 slice 裁剪而得根据下面的 start 与 end 进行个数的裁剪 itemHeight - 列表中每一项的高度 renderCount - 可视区可以渲染的项目数量根据 可视区域的高度 / itemHeight 计算出来因为基本都会有小数问题的可以通过 Math 来进行处理一下 bufferCount - 缓存区的项目个数 start - 截取展示数据的开始索引 end - 截取展示数据的结束索引根据 start renderCount bufferCount 获取但是可能会超出整个列表所有需要根据该计算出来的值需要根据 list.length 取最小值避免 end 超出列表的数据量 currentOffset - 滚动偏移量因为可视区域渲染的元素的个数是基本固定的顺着滚动条的滚动必然也会向上滚动所以可以根据该值对可视区域进行相应偏移量的平移避免随着滚动条滚动根据 滚动大小 - (滚动大小 % itemHeight) 进行获取
代码实现: HTML 结构 template!-- 容器 --div classvirtual-list-container refvirtual-list-container!-- 占位元素: 根据列表数据个数与每一项的大小计算出对应的高度 --div classvirtual-list-placeholder :style{ height: placeholderHeight px }/div!-- 渲染区域: 根据对应的 currentOffset 偏移量将渲染区域进行对应的平移 --div classvirtual-list-content :style{ transform: translateY(${state.currentOffset}px) }!-- 子组件: 循环列表中的每一项 --div classitem v-foritem in showList :keyitem{{ item }}/div/div/div
/templateCSS 样式 style scoped langscss
.virtual-list {-container { /* 容器大小 */width: 100%;height: 100vh;position: relative;overflow: auto;}-placeholder {position: absolute;inset: 0;}-content {position: absolute;inset: 0;}
}.item { /* item 列表项样式 */outline: 1px solid orange;height: 60px;line-height: 60px;text-align: center;
}
/styleJS 部分 script setup
import { computed, onMounted, reactive, useTemplateRef } from vue;const list new Array(20000).fill(null).map((item, i) i 1) // -- 模拟列表数据所有数据
const containerRef useTemplateRef(virtual-list-container) // -- 容器元素// -- 获取相应的状态
const state reactive({start: 0, // -- 开始索引itemHeight: 60, // -- 每项 item 中的高度renderCount: 0, // -- 可视区域可以渲染的项目个数根据容器高度与 itemHeight 进行计算bufferCount: 6, // -- 缓存个数currentOffset: 0, // -- 根据滚动距离获取对应的偏移量
})const end computed(() // -- 计算结束索引Math.min(state.start state.renderCount state.bufferCount,list.length)
)const showList computed(() list.slice(state.start, end.value)) // -- 根据 start 与 end 获取对应需要展示的列表数据onMounted(() {const containerHeight containerRef.value.offsetHeight // -- 获取容器高度state.renderCount Math.round(containerHeight / state.itemHeight) // -- 获取可视区域可渲染个数
})const placeholderHeight list.length * state.itemHeight // -- 占位元素的高度用于给容器撑出对应的滚动条
/script上面的代码已经可以根据对应的视口大小来计算所需要渲染的个数了但是还有一个滚动时的处理为了方便大家阅读所以将滚动条滚动部分的代码放在这下面这些代码直接与上面 JS 部分 进行合并即可 const handleScrollEvent () { // -- 触发滚动事件时所需要处理的操作if (!containerRef.value) returnconst { scrollTop } containerRef.value// -- 根据滚动大小重新计算 start 开始索引因为 end 结束索引是根据该 start 派生的计算属性所以也会自动的进行计算state.start Math.round(scrollTop / state.itemHeight)// -- 根据滚动大小重新计算对应滚动的偏移量用于动态的给可视区域进行对应偏移量的平移state.currentOffset scrollTop - (scrollTop state.itemHeight)
}onMounted(() {if (!containerRef.value) returncontainerRef.value.addEventListener(scroll, handleScrollEvent) // -- 监听容器的滚动
})onUnmounted(() {if (!containerRef.value) returncontainerRef.value.removeEventListener(scroll, handleScrollEvent) // -- 组件卸载时取消监听滚动事件
})通过上面的代码我们就可以简单的实现了一个定高的虚拟列表了
注意:
上面的代码虽然实现了定高的虚拟列表单滚动条的触发频率我们可以通过稍加一点点 节流Throttle 获 防抖Debounce 来降低回调函数的触发频率当然使用防抖还是节流具体看你想要的是一种怎么样的效果当然我们也可以通过 Intersection Observer API 来代替滚动事件的监听来提高对应的性能
总结: 定高虚拟列表实现思路
1. 在 HTML 结构中的处理 (1) - 需要有一个可视窗口的容器 (2) - 容器中需要有一个占位元素用来撑开视口高度使其能够有对应高度的滚动条该元素的高度需要等于: 长列表中的数据长度 * 每个元素的高度 → tip: 如果元素存在 margin 等也需要计算上去 (3) - 容器中还需要有一个内容区域用来存放真正渲染的列表数据该元素需要是一个根据容器元素的一个绝对定位元素用于当滚动条在滚动时该内容区域元素可以根据定位中的 top 属性进行相应滚动距离的平移避免整个容器区域也随着滚动上去当然也可以通过 transform 进行平移
2. 在 JS 中的处理 list - 列表数据所有数据 showList - 所要真正展示的数据在所有数据列表 list 中进行 slice 裁剪而得根据下面的 start 与 end 进行个数的裁剪 itemHeight - 列表中每一项的高度 renderCount - 可视区可以渲染的项目数量根据 可视区域的高度 / itemHeight 计算出来因为基本都会有小数问题的可以通过 Math 来进行处理一下 bufferCount - 缓存区的项目个数 start - 截取展示数据的开始索引 end - 截取展示数据的结束索引根据 start renderCount bufferCount 获取但是可能会超出整个列表所有需要根据该计算出来的值需要根据 list.length 取最小值避免 end 超出列表的数据量 currentOffset - 滚动偏移量因为可视区域渲染的元素的个数是基本固定的顺着滚动条的滚动必然也会向上滚动所以可以根据该值对可视区域进行相应偏移量的平移避免随着滚动条滚动根据 滚动大小 - (滚动大小 % itemHeight) 进行获取
3. onscroll 监听滚动条 : 在滚动条监听的回调中主要需要做如下两件事
(1) - 获取当前的滚动大小并根据该值与对应的 itemHeight 大小计算出新的 start并赋值该对应的 start 状态中(2) - 根据滚动大小动态设置 HTML 中的列表容器.virtual-list中的 top 样式进行对应的平移 → 避免列表容器也随着滚动条的滚动而进行滚动