感觉我讲得好的,请帮忙点个赞,谢谢你们了。嘻嘻
场景
康熙选妃
话说这年是康熙五十三年,天下太平,天下无人不感叹这“康熙盛世”啊,康熙本人也是开心的不得了啊,“朕奋斗了大半辈子,还不能吃苦吃苦,传命张廷玉来见我,我有事要让他办!”
- 康熙:衡臣啊(衡臣是张廷玉的字),这康熙盛世如何
- 张廷玉:皇上牛逼,皇上牛逼,皇上万岁
- 康熙:然而朕老了啊,然而朕不能服老,朕要证实给天下人看
- 张廷玉:皇上正值壮年,万岁万万岁
- 康熙:我不论,我要选妃,我要选妃,我要选妃!!!
- 张廷玉:我 tm。。。你 tm 都 60 了还选?你扛得住吗?大哥!
- 康熙:我不论,你给我去找,找一万个妙龄女子进宫,我要选妃
- 张廷玉:选个毛,你顶不动的 - 康熙:我不论,我有鹿血,鹿血一杯,法力无边
- 张廷玉:不,你不行。
- 康熙:你去不去?
- 张廷玉:不去
- 康熙:你去不去
- 张廷玉:我不去
- 康熙:还想不想配享太庙了?
-
张廷玉:皇上万岁,臣肯定上的圣托
一个月后,一万名妙龄女子进宫了。然而难题又来了。这么多男子,不可能一次性让康熙选吧,那不得花了他的眼睛。
张廷玉眉头一皱; 计上心来:能够让
男子们
分批进大殿
让皇上选嘛。具体能够这么做:
- 在皇上选妃的
大殿
外,再设置两个偏殿
- 宫女们分批次进大殿让皇上看
-
被看过的宫女们进左偏殿期待选妃后果,还没排到的宫女在右偏殿期待
这样既进步了选秀效率,又能够让皇上更轻松些。这样做的益处就是:
- 皇上不须要一次性看一万个宫女,不必那么操劳
- 皇上如果选到一半累了,也能够劳动,隔天再选,反正选到第几批了,这些都曾经记录下了
- 皇上如果某一天回想起哪个宫女还不错,也能够往回查
多数据渲染
当初解决多数据渲染,置信大家可能会想到分页,触底加载,懒加载等等,但其实
虚构列表
也是多数据高性能加载的一个重要解决方案。
虚构列表的概念
虚构滚动,就是依据
容器可视区域
的列表容积数量
,监听用户滑动或滚动事件,动静截取长列表数据
中的局部数据
渲染到页面上,动静应用空白站位填充容器高低滚动区域内容
,模仿实现原生滚动成果
- 浏览器渲染 === 康熙选秀:一次性渲染 10000 个必定会使浏览器压力大,造成用户体验差
- 容器可视区域 === 选秀大殿:10000 个排队去渲染,比方一次渲染 10 个
- 上方下方区域 === 左右偏殿:轮不到你渲染,你就乖乖进空白区待着
实现
根本实现
- 可视区域的高度
- 列表项的高度
- 可视区域能展现的列表项个数 = ~~(可视区域高度 / 列表项高度) + 2
- 开始索引
- 完结索引
- 预加载(避免滚动过快,造成临时白屏)
- 依据开始索引和完结索引,截取数据展现在可视区域
- 滚动节流
- 高低空白区应用 padding 实现
- 滑动到底,再次申请数据并拼接
<template>
<div class="v-scroll" @scroll.passive="doScroll" ref="scrollBox">
<div :style="blankStyle" style="height: 100%">
<div v-for="item in tempSanxins" :key="item.id" class="scroll-item">
<span>{{item.msg}}</span>
<img :src="item.src" />
</div>
</div>
</div>
</template>
<script>
import {throttle} from "../../utils/tools";
export default {data() {
return {allSanxins: [], // 所有数据
itemHiehgt: 150, // 列表每一项的宽度
boxHeight: 0, // 可视区域的高度
startIndex: 0, // 元素开始索引
};
},
created() {
// 模仿申请数据
this.getAllSanxin(30);
},
mounted() {
// 在 mounted 时获取可视区域的高度
this.getScrollBoxHeight();
// 监听屏幕变动以及旋转,都要从新获取可视区域的高度
window.onresize = this.getScrollBoxHeight;
window.onorientationchange = this.getScrollBoxHeight;
},
methods: {getAllSanxin(count) {
// 模仿获取数据
const length = this.allSanxins.length;
for (let i = 0; i < count; i++) {
this.allSanxins.push({id: `sanxin${length + i}`,
msg: ` 我是三心 ${length + i}号 `,
// 这里轻易选一张图片就行
src: require("../../src/asset/images/sanxin.jpg").default,
});
}
},
// 应用节流,进步性能
doScroll: throttle(function () {
// 监听可视区域的滚动事件
// 公式:~~(滚动的间隔 / 列表项),就能算出曾经滚过了多少个列表项,也就能晓得当初的 startIndex 是多少
// 例如我滚动条滚过了 160px,那么 index 就是 1,因为此时第一个列表项曾经被滚上去了,可视区域里的第一项的索引是 1
const index = ~~(this.$refs.scrollBox.scrollTop / this.itemHiehgt);
if (index === this.startIndex) return;
this.startIndex = index;
if (this.startIndex + this.itemNum > this.allSanxins.length - 1) {this.getAllSanxin(30);
}
}, 200),
getScrollBoxHeight() {
// 获取可视区域的高度
this.boxHeight = this.$refs.scrollBox.clientHeight;
},
},
computed: {itemNum() {// 可视区域可展现多少个列表项?计算公式:~~(可视化区域高度 / 列表项高度) + 2
// ~~ 是向下取整的运算符,等同于 Math.floor(),为什么要 +2,是因为可能最下面和最上面的元素都只展现一部分
return ~~(this.boxHeight / this.itemHiehgt) + 2;
},
endIndex() {// endIndex 的计算公式:(开始索引 + 可视区域可展现多少个列表项 * 2)
// 比方可视区域可展现 8 个列表项,startIndex 是 0 的话 endIndex 就是 0 + 8 * 2 = 16,startIndex 是 1 的话 endIndex 就是 1 + 8 * 2 = 17,以此类推
// 为什么要乘 2 呢,因为这样的话能够预加载出一页的数据,避免滚动过快,呈现临时白屏景象
let index = this.startIndex + this.itemNum * 2;
if (!this.allSanxins[index]) {
// 到底的状况,比方 startIndex 是 99995,那么 endIndex 本应该是 99995 + 8 * 2 = 10011
// 然而列表数据总数只有 10000 条,此时就须要让 endIndex = (列表数据长度 - 1)
index = this.allSanxins.length - 1;
}
return index;
},
tempSanxins() {
// 可视区域展现的截取数据,应用了数组的 slice 办法,不扭转原数组又能截取
let startIndex = 0;
if (this.startIndex <= this.itemNum) {startIndex = 0;} else {startIndex = this.startIndex + this.itemNum;}
return this.allSanxins.slice(startIndex, this.endIndex + 1);
},
blankStyle() {
// 上下方的空白处应用 padding 来充当
let startIndex = 0;
if (this.startIndex <= this.itemNum) {startIndex = 0;} else {startIndex = this.startIndex - this.itemNum;}
return {// 上方空白的高度计算公式:(开始 index * 列表项高度)
// 比方你滚过了 3 个列表项,那么上方空白区高度就是 3 * 150 = 450,这样能力伪装 10000 个数据的滚动状态
paddingTop: startIndex * this.itemHiehgt + "px",
// 下方空白的高度计算公式:(总数据的个数 - 完结 index - 1) * 列表项高度
// 例如当初完结 index 是 100,那么下方空白高度就是:(10000 - 100 - 1) * 150 = 1,484,850
paddingBottom:
(this.allSanxins.length - this.endIndex - 1) * this.itemHiehgt + "px",
// 不要忘了加 px 哦
};
},
},
};
</script>
<style lang="scss" scoped>
.v-scroll {
height: 100%;
/* padding-bottom: 500px; */
overflow: auto;
.scroll-item {
height: 148px;
/* width: 100%; */
border: 1px solid black;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
img {height: 100%;}
}
}
</style>
结语!
我是林三心,一个热心的前端菜鸟程序员。如果你上进,喜爱前端,想学习前端,那咱们能够交朋友,一起摸鱼哈哈,摸鱼群,加我请备注【思否】