前言:
一些很直白,不可逃避的问题:
你时间很多吗?
为什么要花时间去写通用组件?
为什么不直接使用UI组件库的东西?
你写的有人家的好吗?
这些问题我大部分也回答不了,或者说给不了清晰的答案
只能说,我还享受着这种在代码世界里做着自己想做的东西的状态
什么是虚拟滚动列表?
通俗的说,就是前端页面永远只渲染几个或者几十个DOM,就能达到滚动展示成千上万条数据的效果,不会造成页面卡顿(核心)。
前端环境:Vue2.5+
1.布局
:style="{ height: listHeight + 'px' }">
:id="`items-${index}`"
v-for="(item, index) in visibleData"
:key="index"
:style="{ height: itemSize + 'px' }"
@click="handleClickItem(item, index)">
type="text"
:loading="loading"
style="width: 100%;color: #515a6e;">
加载更多
2.样式
.virtual-list-container { overflow: auto; position: relative; .analog-scroll-bar { position: relative; left: 0; top: 0; z-index: -1; } .virtual-list { left: 0; top: 0; position: absolute; .virtual-list-item { color: #555; box-sizing: border-box; } .loadMore { width: 100%; } }}
3.js(重点)
export default { name: 'VirtualList', props: { listData: { // 所有列表数据 type: Array, default: () => [] }, itemSize: { // 每项item高度 type: Number, default: 200 }, multipleColumn: { // 一行展示item元素数量, 即一列展示, 还是多列展示, 正整数 type: Number, default: 1 } }, computed: { // 列表总高度, 根据listData的长度, 确定整个列表的高度, 赋值给virtual-list-phantom listHeight () { return Math.ceil((this.listData.length * this.itemSize) / this.multipleColumn) }, // 根据虚拟列表区域高度, 计算能展示的数据量 visibleCount () { return Math.ceil(this.screenHeight / this.itemSize) * this.multipleColumn }, // 偏移量对应的style,模拟滚动 getTransform () { return `translateY(${this.startOffset}px)` }, // 真正渲染的数据 visibleData () { return this.listData.slice(this.startIndex, (Math.min(this.endIndex, this.listData.length) + 1)) } showLoadMore () { return this.endIndex>= this.listData.length } }, watch: { listData: { handler (v) { this.$nextTick(() => { this.initData() this.loading = false }) }, immediate: true // 立即执行一次 } }, data () { return { screenHeight: 0, // 可视区域高度或者说列表容器的高度 startOffset: 0, // 偏移量 startIndex: 0, // 起始索引 endIndex: null, // 结束索引 loading: false } }, methods: { initData () { this.screenHeight = this.$el.clientHeight // 当前组件的DOM元素高度 // 点击加载更多的时候, 如果重置了startIndex, 就会出现从头开始截取可视数据, 造成显示不正确 this.startIndex = this.startIndex ? this.startIndex : 0 this.endIndex = this.startIndex + this.visibleCount }, handleScrollEvent () { // 当前滚动位置 let scrollTop = this.$refs.virtualList.scrollTop // 根据滚动的距离重新计算起始索引 this.startIndex = Math.floor(scrollTop / this.itemSize) * this.multipleColumn // 根据滚动的距离重新计算结束索引 this.endIndex = this.startIndex + this.visibleCount // 此时的偏移量 this.startOffset = scrollTop - (scrollTop % this.itemSize) }, // 点击回调 handleClick (item) { this.$emit('on-click', item) }, // 加载更多回调 handleLoadMore () { this.loading = true this.$emit('on-load', true) } }}
虚拟滚动列表的核心在于:
1、监听滚动事件,动态计算开始和结束索引,获取真正渲染到页面上的数据
2、监听滚动事件,动态计算偏移量,模拟滚动效果
以上就基本写好了一个虚拟滚动列表的组件模板了
理解了核心点后,自动动手写一个还是不难的,
如果自己项目中有长列表需求,可以尝试用一下