前言:
今天我们对“div 最上层”大约比较重视,看官们都需要知道一些“div 最上层”的相关文章。那么小编在网摘上汇集了一些对于“div 最上层””的相关资讯,希望看官们能喜欢,咱们快快来学习一下吧!什么是虚拟列表
虚拟列表是指对列表的 可视区域 进行渲染,对 非可见区域 不渲染或部分渲染,从而极大提高渲染性能的一种技术。
为什么要用虚拟列表
有时我们会遇到一些业务场景,要展示的列表很长,且不能使用分页的方式,如果一次性把数据全部渲染到页面,浏览器将变得非常卡顿,因为渲染 dom 需要耗费大量时间。虚拟列表 就是对长列表的一种优化方式,通过只渲染可视区域数据,大大提高渲染性能。
如何使用虚拟列表
目前虚拟列表已经有很多知名的库,如 vue-virtual-scroller、vue-virtual-scroll-list、react-virtualized 等, 下面就给大家介绍一下 vue-virtual-scroller 这个优秀库的使用方法,然后再带大家实现一个简版的虚拟列表。准备好了吗,开干!
安装
npm install --save vue-virtual-scrollerRecycleScroller组件
适用于列表每一项高度确定的情况,高度可设置成相同,也可单独配置每一项高度。
src/components/virtualRecycleScroller.vue
<template> <RecycleScroller class="scroller" :items="items" :item-size="50" key-field="id" v-slot="{ item }" > <div class="desc"> {{ item.label }} </div> </RecycleScroller> <!-- items: 需要渲染的列表,itemSize: 列表项的高度,keyField: 列表循环的key值 --></template><script>import { RecycleScroller } from 'vue-virtual-scroller'import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'export default { components: { RecycleScroller }, props: { items: Array }}</script><style scoped>.scroller { height: 100%;}.desc { height: 50px; line-height: 50px; text-align: center; box-sizing: border-box; border: 1px solid #ccc;}</style>
src/App.vue
<template> <div class="container"> <virtual-recycle-scroller :items="list" /> </div></template><script>import virtualRecycleScroller from '@/components/virtualRecycleScroller'// 模拟一个长列表const list = []for(let i=0; i<10000; i++) { list.push({ id: i, label: `virtual-list ${i}` })}export default { components: { virtualRecycleScroller }, data() { return { list: list } }}</script><style scoped>.container { height: 300px; border: 1px solid #ccc;}</style>
效果如下:
一万条数据的列表瞬间就渲染出来了,滚动也丝滑无比,是不是很nice!
DynamicScroller组件
适用于列表每一项高度不确定的情况。
src/components/virtualDynamicScroller.vue
<template> <DynamicScroller class="scroller" :items="items" :min-item-size="50"> <template v-slot="{ item, index, active }"> <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.label]" :data-index="index" > <div class="desc">{{ item.label }}</div> </DynamicScrollerItem> </template> </DynamicScroller> <!-- minItemSize: 列表项初次渲染使用的最小高度--> <!-- active: 保持视图,防止不必要的重新计算 --> <!-- sizeDependencies: 影响高度的值,如果发生变化,则重新计算 --></template><script>import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'export default { components: { DynamicScroller, DynamicScrollerItem }, props: { items: Array }}</script><style scoped>.scroller { height: 100%;}.desc { padding: 12px; text-align: center; border: 1px solid #ccc;}</style>
src/App.vue
<template> <div class="container"> <virtual-dynamic-scroller :items="list" /> </div></template><script>import virtualDynamicScroller from '@/components/virtualDynamicScroller.vue'// 模拟一个长列表const list = []for(let i=0; i<10000; i++) { list.push({ id: i, label: `virtual-scroller ${i}` })}// 模拟一个内容不同的列表项list[2].label = `virtual-scroller 2 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 前端阿飞 `export default { components: { virtualDynamicScroller }, data() { return { list: list } }}</script><style scoped>.container { height: 300px; border: 1px solid #ccc;}</style>
效果如下:
可以看到列表项的高度是随内容的变化而变化,依旧是丝滑无比!
虚拟列表原理
初次听到 “虚拟列表” 这个名词感觉非常的高大上,其实弄清楚它的原理之后,你会发现它非常的简单。话不多说,先上图:
可视区容器:可以看作是在最底层,容纳所有元素的一个盒子。可滚动区域:可以看作是中间层,假设有 10000 条数据,每个列表项的高度是 50,那么可滚动的区域的高度就是 10000 * 50。这一层的元素是不可见的,目的是产生和真实列表一模一样的滚动条。可视区列表:可以看作是在最上层,展示当前处理后的数据,高度和可视区容器相同。可视区列表的位置是动态变化的,为了使其始终出现在可视区域。
理解以上概念之后,我们再看看当滚动条滚动时,我们需要做什么:
根据滚动距离和 item 高度,计算出当前需要展示的列表的 startIndex根据 startIndex 和 可视区高度,计算出当前需要展示的列表的 endIndex根据 startIndex 和 endIndex 截取相应的列表数据,赋值给可视区列表,并渲染在页面上根据滚动距离和 item 高度,计算出可视区列表的偏移距离 startOffset,并设置在列表上
原理就是这些,不知道大家有木有听明白。俗话说 “书读百遍,其义自现” ,但我更相信 “实践出真知” ,接下来我们就自己动手实现一个虚拟列表吧!
手写一个简版的虚拟列表
src/components/myVirtualScroller.vue
<template> <!-- 最底层的可视区容器 --> <div ref="list" class="infinite-list-container" @scroll="scrollEvent($event)"> <!-- 中间的可滚动区域,z-index=-1,高度和真实列表相同,目的是出现相同的滚动条 --> <div class="infinite-list-phantom" :style="{ height: listHeight + 'px' }"></div> <!-- 最上层的可视区列表,数据和偏移距离随着滚动距离的变化而变化 --> <div class="infinite-list" :style="{ transform: getTransform }"> <div class="infinite-list-item" v-for="item in visibleData" :key="item.id" :style="{ height: itemSize + 'px' }" > {{ item.label }} </div> </div> </div></template><script>export default { name: 'MyVirtualList', props: { //列表数据 items: { type: Array, default: () => [] }, //列表项高度 itemSize: { type: Number, default: 50 } }, computed: { //列表总高度 listHeight() { return this.items.length * this.itemSize }, //可视区列表的项数 visibleCount() { return Math.ceil(this.screenHeight / this.itemSize) }, //可视区列表偏移距离对应的样式 getTransform() { return `translate3d(0,${this.startOffset}px,0)` }, //获取可视区列表数据 visibleData() { return this.items.slice(this.start, Math.min(this.end, this.items.length)) } }, mounted() { this.screenHeight = this.$refs.list.clientHeight this.start = 0 this.end = this.start + this.visibleCount }, data() { return { screenHeight: 0, //可视区域高度 startOffset: 0, //偏移距离 start: 0, //起始索引 end: 0 //结束索引 } }, methods: { scrollEvent() { //当前滚动位置 let scrollTop = this.$refs.list.scrollTop //此时的开始索引 this.start = Math.floor(scrollTop / this.itemSize) //此时的结束索引 this.end = this.start + this.visibleCount //此时的偏移距离 this.startOffset = scrollTop - (scrollTop % this.itemSize) } }}</script><style scoped>.infinite-list-container { height: 100%; overflow: auto; position: relative;}.infinite-list-phantom { position: absolute; left: 0; top: 0; right: 0; z-index: -1;}.infinite-list { left: 0; right: 0; top: 0; position: absolute;}.infinite-list-item { line-height: 50px; text-align: center; color: #555; border: 1px solid #ccc; box-sizing: border-box;}</style>
src/App.vue
<template> <div class="container"> <my-virtual-scroller :items="list" /> </div></template><script>import myVirtualScroller from '@/components/myVirtualScroller'// 模拟一个长列表const list = []for(let i=0; i<10000; i++) { list.push({ id: i, label: `virtual-list ${i}` })}export default { components: { myVirtualScroller }, data() { return { list: list } }}</script><style scoped>.container { height: 300px; border: 1px solid #ccc;}</style>
效果和上面基本是一样:
以上就是简版的虚拟列表,大家可以自己动手试一试。如果要做的更加完善,还需考虑缓冲区域、列表项高度自适应等,有兴趣的同学可以自己研究一哈。
今天的分享就到这里,相信下次遇到这种场景你应该知道怎么处理了。你的支持就是我最大的动力,如果文章对你有所帮助,不要忘了点个免费的赞呦~
Demo地址:
标签: #div 最上层