結(jié)合康熙選秀講解vue虛擬列表實(shí)現(xiàn)
場(chǎng)景
康熙選妃
話說(shuō)這年是康熙五十三年,天下太平,天下無(wú)人不感嘆這“康熙盛世”啊,康熙自己也是開(kāi)心的不得了啊,“朕奮斗了大半輩子,還不能享樂(lè)享樂(lè),傳命張廷玉來(lái)見(jiàn)我,我有事要讓他辦!”
- 康熙:衡臣啊(衡臣是張廷玉的字),這康熙盛世如何
- 張廷玉:皇上牛逼,皇上牛逼,皇上萬(wàn)歲
- 康熙:但是朕老了啊,但是朕不能服老,朕要證明給天下人看
- 張廷玉:皇上正值壯年,萬(wàn)歲萬(wàn)萬(wàn)歲
- 康熙:我不管,我要選妃,我要選妃,我要選妃?。?!
- 張廷玉:我tm。。。你tm都60了還選?你扛得住嗎?大哥!
- 康熙: 我不管,你給我去找,找一萬(wàn)個(gè)妙齡女子進(jìn)宮,我要選妃
- 張廷玉:選個(gè)毛,你頂不動(dòng)的- 康熙:我不管,我有鹿血,鹿血一杯,法力無(wú)邊
- 張廷玉:不,你不行。
- 康熙:你去不去?
- 張廷玉:不去
- 康熙: 你去不去
- 張廷玉:我不去
- 康熙:還想不想配享太廟了?
- 張廷玉:皇上萬(wàn)歲,臣一定上的圣托
一個(gè)月后,一萬(wàn)名妙齡女子進(jìn)宮了。但是難題又來(lái)了。這么多女子,不可能一次性讓康熙選吧,那不得花了他的眼睛。
張廷玉靈機(jī)一動(dòng):可以讓女子們分批進(jìn)大殿讓皇上選嘛。具體可以這么做:
- 在皇上選妃的大殿外,再設(shè)置兩個(gè)偏殿
- 宮女們分批次進(jìn)大殿讓皇上看
- 被看過(guò)的宮女們進(jìn)左偏殿等待選妃結(jié)果,還沒(méi)排到的宮女在右偏殿等待
這樣既提高了選秀效率,又可以讓皇上更輕松些。這樣做的好處就是:
- 皇上不需要一次性看一萬(wàn)個(gè)宮女,不用那么勞累
- 皇上如果選到一半累了,也可以休息,隔天再選,反正選到第幾批了,這些都已經(jīng)記錄下了
- 皇上如果某一天回想起哪個(gè)宮女還不錯(cuò),也可以往回查
多數(shù)據(jù)渲染
現(xiàn)在解決多數(shù)據(jù)渲染,相信大家可能會(huì)想到分頁(yè),觸底加載,懶加載等等,但其實(shí)虛擬列表也是多數(shù)據(jù)高性能加載的一個(gè)重要解決方案。
虛擬列表的概念
虛擬滾動(dòng),就是根據(jù)容器可視區(qū)域的列表容積數(shù)量,監(jiān)聽(tīng)用戶滑動(dòng)或滾動(dòng)事件,動(dòng)態(tài)截取長(zhǎng)列表數(shù)據(jù)中的部分?jǐn)?shù)據(jù)渲染到頁(yè)面上,動(dòng)態(tài)使用空白站位填充容器上下滾動(dòng)區(qū)域內(nèi)容,模擬實(shí)現(xiàn)原生滾動(dòng)效果

- 瀏覽器渲染===康熙選秀:一次性渲染10000個(gè)肯定會(huì)使瀏覽器壓力大,造成用戶體驗(yàn)差
- 容器可視區(qū)域===選秀大殿:10000個(gè)排隊(duì)去渲染,比如一次渲染10個(gè)
- 上方下方區(qū)域===左右偏殿:輪不到你渲染,你就乖乖進(jìn)空白區(qū)待著
實(shí)現(xiàn)
基本實(shí)現(xiàn)
- 可視區(qū)域的高度
- 列表項(xiàng)的高度
- 可視區(qū)域能展示的列表項(xiàng)個(gè)數(shù) = ~~(可視區(qū)域高度 / 列表項(xiàng)高度) + 2
- 開(kāi)始索引
- 結(jié)束索引
- 預(yù)加載(防止?jié)L動(dòng)過(guò)快,造成暫時(shí)白屏)
- 根據(jù)開(kāi)始索引和結(jié)束索引,截取數(shù)據(jù)展示在可視區(qū)域
- 滾動(dòng)節(jié)流
- 上下空白區(qū)使用padding實(shí)現(xiàn)
- 滑動(dòng)到底,再次請(qǐng)求數(shù)據(jù)并拼接
<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: [], // 所有數(shù)據(jù)
itemHiehgt: 150, // 列表每一項(xiàng)的寬度
boxHeight: 0, // 可視區(qū)域的高度
startIndex: 0, // 元素開(kāi)始索引
};
},
created() {
// 模擬請(qǐng)求數(shù)據(jù)
this.getAllSanxin(30);
},
mounted() {
// 在mounted時(shí)獲取可視區(qū)域的高度
this.getScrollBoxHeight();
// 監(jiān)聽(tīng)屏幕變化以及旋轉(zhuǎn),都要重新獲取可視區(qū)域的高度
window.onresize = this.getScrollBoxHeight;
window.onorientationchange = this.getScrollBoxHeight;
},
methods: {
getAllSanxin(count) {
// 模擬獲取數(shù)據(jù)
const length = this.allSanxins.length;
for (let i = 0; i < count; i++) {
this.allSanxins.push({
id: `sanxin${length + i}`,
msg: `我是三心${length + i}號(hào)`,
// 這里隨便選一張圖片就行
src: require("../../src/asset/images/sanxin.jpg").default,
});
}
},
// 使用節(jié)流,提高性能
doScroll: throttle(function () {
// 監(jiān)聽(tīng)可視區(qū)域的滾動(dòng)事件
// 公式:~~(滾動(dòng)的距離 / 列表項(xiàng) ),就能算出已經(jīng)滾過(guò)了多少個(gè)列表項(xiàng),也就能知道現(xiàn)在的startIndex是多少
// 例如我滾動(dòng)條滾過(guò)了160px,那么index就是1,因?yàn)榇藭r(shí)第一個(gè)列表項(xiàng)已經(jīng)被滾上去了,可視區(qū)域里的第一項(xiàng)的索引是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() {
// 獲取可視區(qū)域的高度
this.boxHeight = this.$refs.scrollBox.clientHeight;
},
},
computed: {
itemNum() {
// 可視區(qū)域可展示多少個(gè)列表項(xiàng)? 計(jì)算公式:~~(可視化區(qū)域高度 / 列表項(xiàng)高度) + 2
// ~~是向下取整的運(yùn)算符,等同于Math.floor(),為什么要 +2 ,是因?yàn)榭赡茏钌厦婧妥钕旅娴脑囟贾徽故疽徊糠?
return ~~(this.boxHeight / this.itemHiehgt) + 2;
},
endIndex() {
// endIndex的計(jì)算公式:(開(kāi)始索引 + 可視區(qū)域可展示多少個(gè)列表項(xiàng) * 2)
// 比如可視區(qū)域可展示8個(gè)列表項(xiàng),startIndex是0的話endIndex就是0 + 8 * 2 = 16,startIndex是1的話endIndex就是1 + 8 * 2 = 17,以此類(lèi)推
// 為什么要乘2呢,因?yàn)檫@樣的話可以預(yù)加載出一頁(yè)的數(shù)據(jù),防止?jié)L動(dòng)過(guò)快,出現(xiàn)暫時(shí)白屏現(xiàn)象
let index = this.startIndex + this.itemNum * 2;
if (!this.allSanxins[index]) {
// 到底的情況,比如startIndex是99995,那么endIndex本應(yīng)該是99995 + 8 * 2 = 10011
// 但是列表數(shù)據(jù)總數(shù)只有10000條,此時(shí)就需要讓endIndex = (列表數(shù)據(jù)長(zhǎng)度 - 1)
index = this.allSanxins.length - 1;
}
return index;
},
tempSanxins() {
// 可視區(qū)域展示的截取數(shù)據(jù),使用了數(shù)組的slice方法,不改變?cè)瓟?shù)組又能截取
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來(lái)充當(dāng)
let startIndex = 0;
if (this.startIndex <= this.itemNum) {
startIndex = 0;
} else {
startIndex = this.startIndex - this.itemNum;
}
return {
// 上方空白的高度計(jì)算公式:(開(kāi)始index * 列表項(xiàng)高度)
// 比如你滾過(guò)了3個(gè)列表項(xiàng),那么上方空白區(qū)高度就是3 * 150 = 450,這樣才能假裝10000個(gè)數(shù)據(jù)的滾動(dòng)狀態(tài)
paddingTop: startIndex * this.itemHiehgt + "px",
// 下方空白的高度計(jì)算公式:(總數(shù)據(jù)的個(gè)數(shù) - 結(jié)束index - 1) * 列表項(xiàng)高度
// 例如現(xiàn)在結(jié)束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>以上就是結(jié)合康熙選秀講解vue虛擬列表的詳細(xì)內(nèi)容,更多關(guān)于vue虛擬列表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- vue實(shí)現(xiàn)不定高虛擬列表的示例詳解
- 不同場(chǎng)景下Vue中虛擬列表實(shí)現(xiàn)
- 詳解vue3中虛擬列表組件的實(shí)現(xiàn)
- Vue中虛擬列表的原理與實(shí)現(xiàn)詳解
- 基于Vue實(shí)現(xiàn)封裝一個(gè)虛擬列表組件
- vue長(zhǎng)列表優(yōu)化之虛擬列表實(shí)現(xiàn)過(guò)程詳解
- Vue 虛擬列表的實(shí)戰(zhàn)示例
- vue實(shí)現(xiàn)虛擬列表功能的代碼
- 使用 Vue 實(shí)現(xiàn)一個(gè)虛擬列表的方法
- vue簡(jiǎn)單實(shí)現(xiàn)一個(gè)虛擬列表的示例代碼
相關(guān)文章
Vue使用xlsx模塊實(shí)現(xiàn)讀寫(xiě)Excel文檔內(nèi)容
在前端項(xiàng)目開(kāi)發(fā)中,讀寫(xiě)Excel文件的需求變得越來(lái)越常見(jiàn),本文將詳細(xì)介紹如何在Vue項(xiàng)目中利用FileReader對(duì)象和xlsx模塊來(lái)讀取Excel文件的內(nèi)容,需要的可以參考下2024-03-03
vue文件上傳Required request part ‘file‘ is&n
這篇文章主要介紹了vue文件上傳Required request part ‘file‘ is not present問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
validate?注冊(cè)頁(yè)的表單數(shù)據(jù)校驗(yàn)實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了validate?注冊(cè)頁(yè)的表單數(shù)據(jù)校驗(yàn)實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
vue使用Vue.extend方法仿寫(xiě)個(gè)loading加載中效果實(shí)例
在vue中提供v-loading命令,用于div的loading加載,下面這篇文章主要給大家介紹了關(guān)于vue使用Vue.extend方法仿寫(xiě)個(gè)loading加載中效果的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
uniapp微信小程序axios庫(kù)的封裝及使用詳細(xì)教程
這篇文章主要給大家介紹了關(guān)于uniapp微信小程序axios庫(kù)的封裝及使用的相關(guān)資料,Axios是一個(gè)基于promise網(wǎng)絡(luò)請(qǐng)求庫(kù),作用于node.js和瀏覽器中axios-miniprogram-adapteraxios的小程序適配器,需要的朋友可以參考下2023-08-08
Vue中對(duì)watch的理解(關(guān)鍵是immediate和deep屬性)
watch偵聽(tīng)器,是Vue實(shí)例的一個(gè)屬性,是用來(lái)響應(yīng)數(shù)據(jù)的變化,需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷(xiāo)較大的操作時(shí),這個(gè)方式是最有用的,這篇文章主要介紹了Vue中對(duì)watch的理解,需要的朋友可以參考下2022-11-11

