結合康熙選秀講解vue虛擬列表實現
場景
康熙選妃
話說這年是康熙五十三年,天下太平,天下無人不感嘆這“康熙盛世”啊,康熙自己也是開心的不得瞭啊,“朕奮鬥瞭大半輩子,還不能享樂享樂,傳命張廷玉來見我,我有事要讓他辦!”
- 康熙:衡臣啊(衡臣是張廷玉的字),這康熙盛世如何
- 張廷玉:皇上牛逼,皇上牛逼,皇上萬歲
- 康熙:但是朕老瞭啊,但是朕不能服老,朕要證明給天下人看
- 張廷玉:皇上正值壯年,萬歲萬萬歲
- 康熙:我不管,我要選妃,我要選妃,我要選妃!!!
- 張廷玉:我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>
以上就是結合康熙選秀講解vue虛擬列表的詳細內容,更多關於vue虛擬列表的資料請關註WalkonNet其它相關文章!