网站模板免费网盘,雄安做网站价格,公司网站建设制作全,公司营销型网站前端虚拟滚动列表
在大型的企业级项目中经常要渲染大量的数据#xff0c;这种长列表是一个很普遍的场景#xff0c;当列表内容越来越多就会导致页面滑动卡顿、白屏、数据渲染较慢的问题#xff1b;大数据量列表性能优化#xff0c;减少真实dom的渲染 看图#xff1a;绿色…前端虚拟滚动列表
在大型的企业级项目中经常要渲染大量的数据这种长列表是一个很普遍的场景当列表内容越来越多就会导致页面滑动卡顿、白屏、数据渲染较慢的问题大数据量列表性能优化减少真实dom的渲染 看图绿色是显示区域绿色和蓝色中间属于预加载解决滚动闪屏问题大致了解了流程在往下看
实现效果
先说一下你看到这么多真实dom节点是因为做了预加载减少滚动闪屏现象这里写了300行可以根据实际情况进行截取
实现思路
虚拟列表滚动大致思路两个div容器 外层外部容器用来固定列表容器的高度同时生成滚动条内层内部容器用来装元素高度是所有元素高度的和外层容器鼠标滚动事件 dom.scrollTop 获取滚动条的位置根据每行列表的高以及当前滚动条的位置利用slice() 去截取当前需要显示的内容重点滚动条的高度是有内层容器的paddingBottom 和 paddingTop 属性顶起来了确保滚动条位置的准确性这里鼠标上下滚动会出现闪屏问题解决方案如下方案一 预加载向下预加载比如div滚动区域显示30行就预加载 300行( 即这里 slice(startIndex,startIndex 300) )向上预加载在滚动监听事件函数中computeRow判断inner的paddingTop和paddingBottom即可当然这里的download-box的padding有30px像素在加一个divoverflowhidded就解决了方案二缩小滚动范围或者节流时间缩短这里写的500ms具体代码 templatediv classenndiv classdownload-box txt idscrollable-div scrollhandleScrolldiv idinnerdiv v-for(item, index) in data2 :keyindex classline-boxdiv :class{ text-box: props.collapsed, text-box-samll: !props.collapsed }{{ item }}/div/div/div/div/div/templatescript langts setupimport { onMounted, PropType, ref } from vue;import { useText } from ./hooks/useText;const props defineProps({baseData: {type: Object as PropType{taskId: string;barcodeName: string;},default: {},},collapsed: {type: Boolean,default: true,},type: {type: Boolean,default: false,},});const { data } useText(props.type);// 这里大数据量数组是 data.geneTexts/*** 虚拟列表滚动大致思路两个div容器** 外层外部容器用来固定列表容器的高度同时生成滚动条** 内层内部容器用来装元素高度是所有元素高度的和** 外层容器鼠标滚动事件 dom.scrollTop 获取滚动条的位置** 根据每行列表的高以及当前滚动条的位置利用slice() 去截取当前需要显示的内容** 重点滚动条的高度是有内层容器的paddingBottom 和 paddingTop 属性顶起来了确保滚动条位置的准确性** 这里鼠标上下滚动会出现闪屏问题解决方案如下** 方案一 预加载** 向下预加载* 比如div滚动区域显示30行就预加载 300行( 即这里 slice(startIndex,startIndex 300) )** 向上预加载* 在滚动监听事件函数中computeRow判断inner的paddingTop和paddingBottom即可** 当然这里的download-box的padding有30px像素在加一个divoverflowhidded就解决了** 方案二缩小滚动范围或者节流时间缩短这里写的500ms***/let timer_throttle: any;const throttle (func: Function, wait?: number) {wait wait || 500;if (!timer_throttle) {timer_throttle setTimeout(() {func.apply(this);timer_throttle null;}, wait);}};// 鼠标滚动事件const handleScroll (event: any) throttle(computeRow, 100);// 计算当前显示tabconst computeRow () {// console.log(距离顶部距离, window.scrollY, geneTexts);let scrollableDiv document.getElementById(scrollable-div);let topPosition scrollableDiv.scrollTop;let leftPosition scrollableDiv.scrollLeft;console.log(垂直滚动位置:, topPosition, 水平滚动位置:, leftPosition);const startIndex Math.max(0, Math.floor(topPosition / 30));const endIndex startIndex 300;data2.value data.geneTexts.slice(startIndex, endIndex);let inner document.getElementById(inner);if (topPosition 2700) {// 向上预计加载这里判断了三个高度可以多判断几个增加流畅度inner.style.paddingTop topPosition px;inner.style.paddingBottom (data.geneTexts.length 2) * 30 - topPosition px;} else if (topPosition data2.value.length * 30 data.geneTexts.length * 30) {// 这里 9000 是 内层div的高度 30 * 300 理解div高度是 paddingdiv内容高度inner.style.paddingTop topPosition - 900 px; //900 是div的高度inner.style.paddingBottom 0 px;} else {inner.style.paddingTop topPosition - 2700 px;inner.style.paddingBottom (data.geneTexts.length 2) * 30 2700 - topPosition px;}};const data2 ref([]);const init () {data2.value data.geneTexts.slice(0, 300);let inner document.getElementById(inner);inner.style.paddingTop 0 px;inner.style.paddingBottom (data.geneTexts.length 2) * 30 - 900 px;};/scriptstyle langless scoped.button-box {margin-bottom: 25px;.flex-type(flex-end);:deep(.ant-btn) {margin-left: 10px;}}.enn {background: #282c34;outline: 1px solid red;padding: 30px 20px;height: 960px;}.download-box {width: 100%;// padding: 30px 20px;outline: 1px solid rgb(17, 0, 255);background-color: #fff;overflow: hidden;.line-box {.flex-type(flex-start);height: 30px;}.txt {background: #282c34;color: #fff;height: 900px;overflow: auto;}}/style
替代方案
上面是自己写的github上面还有好多插件可以用但各有优劣根据自己需求选择 如
vue-virtual-scroller
https://github.com/Akryum/vue-virtual-scroller/tree/0f2e36248421ad69f41c9a08b8dcf7839527b8c2
vue-virt-list
vue-draggable-virtual-scroll-list
virtual-list
自己找吧我就不一一列举了看图