DOM节点过多会影响页面性能,推荐的最多节点数量1500。
实现原理
代码
前置知识点
- 节流防抖
transform:translateY:
| 属性 | 用法 |
|---|---|
| translate(x,y) | ⽔平⽅向和垂直⽅向同时移动 |
| translateX(X) | ⽅向移动 X 轴移动 |
| translateY(Y) | ⽅向移动 Y 轴移动 |
<template>
<!-- 顶部标题 -->
<div class="list" @scroll="scrollHandle" ref="list">
<div
class="item"
v-for="(item, index) in renderList"
:key="index"
:style="
`height:${itemHeight}px;line-height:${itemHeight}px;transform:translateY(${top}px)`
"
>
{{ item }}
</div>
</div>
</template>
<script>
import throttle from './throttle'
export default {
name: 'App',
data () {
return {
list: [], // 完整列表
itemHeight: 60, // 每一项的高度
renderList: [], // 需要渲染的列表
start: 0, // 开始渲染的位置
volume: 0, // 页面的容积:能装下多少个节点
top: 0,
scroll // 用于初始化节流
}
},
mounted () {
this.initList()
const cHeight = document.documentElement.clientHeight
// 计算页面能容纳下几个节点并且设置四个节点作为冗余
this.volume = Math.ceil(cHeight / this.itemHeight) + 4
// 设置要渲染的列表 设置成能够容纳下的最大元素个数
this.renderList = this.list.slice(0, this.volume)
// 初始化节流函数 最短50毫秒触发一次
this.scroll = throttle(this.onScroll, 50)
},
methods: {
// 初始化列表 ,循环渲染 500条
initList () {
for (let i = 0; i < 500; i++) {
this.list.push(i)
}
},
scrollHandle () {
this.scroll()
},
onScroll () {
const scrollTop = this.$refs.list.scrollTop // scrollTop常量记录当前滚动的高度
// const scrollHeight = this.$refs.list.scrollHeight // scrollTop常量记录当前滚动的高度
// console.log('【 已向上滚动的高度 】-61', scrollTop)
const start = this.getCurStart(scrollTop) // 已向上滚动了多少个item
// console.log('【 已向上滚动了多少个item 】-63', start)
// 对比上一次的开始节点 比较是否发生变化,发生变化后便重新渲染列表
if (this.start !== start) {
// 在这需要获得一个可以被itemHeight整除的数(减去100%)来作为item的偏移量
const offsetY = scrollTop - (scrollTop % this.itemHeight) // scrollTop % this.itemHeight:减去余数,确保可以整除
// console.log('【 item的偏移量 】-68', offsetY, scrollTop % this.itemHeight)
// 使用slice拿到需要渲染的那一部分
this.renderList = this.list.slice(
start,
this.start + this.volume
)
// 这里的top用于设置translateY transform:translateY(${top}px)
this.top = offsetY // 每个item向上滚动的滑动的位置
}
this.start = start
},
// 已向上滚动了多少个item
getCurStart (scrollTop) {
// 卷去了多少个
return Math.floor(scrollTop / this.itemHeight) // math.floor(x)返回小于参数x的最大整数 6.5->6
}
}
}
</script>
<style lang="less" scoped>
* {
margin: 0;
padding: 0;
}
.list {
height: 100vh;
overflow: scroll;
}
.item {
text-align: center;
width: 100%;
box-sizing: border-box;
border-bottom: 1px solid lightgray;
}
</style>
参考链接: