vxe-list?vue?如何實現(xiàn)下拉框的虛擬列表
vxe-list vue下拉框的虛擬列表
vxe-table vxe-list vue 實現(xiàn)下拉框的虛擬列表
虛擬列表的實現(xiàn)原理
只渲染可視區(qū)的 dom 節(jié)點,其余不可見的數(shù)據(jù)卷起來,只會渲染可視區(qū)域的 dom 節(jié)點,提高渲染性能及流暢性,優(yōu)點是支持海量數(shù)據(jù)的渲染;當然也會有缺點:滾動效果相對略差(海量數(shù)據(jù)與滾動效果的取舍問題就看自己的需求嘍);
<div class="my-select">
? ?<input type="text" class="my-select-input" readonly>
? ? <vxe-list class="my-select-wrapper" :loading="loading" :data="list">
? ? ? ? <template v-slot="{ items }">
? ? ? ? ? ? <div class="my-select-option" v-for="item in items" :key="item.value">{{ item.label }}</div>
? ? ? ? </template>
? ? </vxe-list>
</div>export default {
data () {
return {
loading: false,
list: []
}
},
created () {
this.loading = true
setTimeout(() => {
const startTime = Date.now()
var list = []
for(var i=0;i<100000;i++){
list.push({
label: '選項'+i,
value: i
})
}
this.list = list
this.loading = false
this.$nextTick(() => {
this.$XModal.message({ message: `渲染 ${list.length} 行,用時 ${Date.now() - startTime}毫秒`, status: 'info' })
})
}, 200)
}
}.my-select {
width: 200px;
position: relative;
background-color: #fff;
}
.my-select-input {
width: 100%;
height: 24px;
border: 1px solid #dcdfe6;
}
.my-select-wrapper {
position: absolute;
left: 0;
top: 26px;
width: 100%;
height: 200px;
background-color: #fff;
border: 1px solid #dcdfe6;
}
.my-select-option:hover {
background-color: #f5f7fa;
cursor: pointer;
}
接下來測試一下
渲染 1w 條只需要 150 毫秒左右
渲染 5w 條只需要 300 毫秒左右
渲染 10w 條只需要 500 毫秒左右
具體用法可以去看 官方文檔,在線運行 http://jsrun.net/CW2Kp/edit
vue虛擬列表實現(xiàn)原理
應用場景
前端的業(yè)務開發(fā)中會遇到不使用分頁方式來加載長列表的需求。如在數(shù)據(jù)長度大于 1000 條情況,DOM 元素的創(chuàng)建和渲染需要的時間成本很高,完整渲染列表所需要的時間不可接受,同時會存在滾動時卡頓問題;
解決該卡頓問題的重點在于如何降低長列表DOM渲染成本問題,文章將介紹通過虛擬列表渲染的方式解決該問題。
為什么需要虛擬列表
虛擬列表是對長列表的一種優(yōu)化方案。在前端開發(fā)中,會碰到一些不能使用分頁方式來加載列表數(shù)據(jù)的業(yè)務形態(tài),我們稱這種列表叫做長列表。比如,手機端,淘寶商品展示,美團外賣等,數(shù)據(jù)量特別龐大,不適合分頁,以及懶加載,這時候我們可以采用虛擬列表,只展示可視區(qū)域數(shù)據(jù)。
實現(xiàn)思路
虛擬列表的核心思想為可視區(qū)域渲染,在頁面滾動時對數(shù)據(jù)進行截取、復用DOM進行展示的渲染方式。
實現(xiàn)虛擬列表就是處理滾動條滾動后的可見區(qū)域的變更,其中具體步驟如下:
1.計算當前可見區(qū)域起始數(shù)據(jù)的 startIndex
2.計算當前可見區(qū)域結(jié)束數(shù)據(jù)的 endIndex
3.計算當前可見區(qū)域的數(shù)據(jù),并渲染到頁面中
4.計算 startIndex 對應的數(shù)據(jù)在整個列表中的偏移位置 startOffset,并設置到列表上

基礎實現(xiàn)
我們首先要考慮的是虛擬列表的 HTML、CSS 如何實現(xiàn):
- 列表元素(.list-view)使用相對定位
- 使用一個不可見元素(.list-view-phantom)撐起這個列表,讓列表的滾動條出現(xiàn)
- 列表的可見元素(.list-view-content)使用絕對定位,left、right、top 設置為 0
html:
<template>
<div
class="list-view"
:style="{
height: `${height}px`
}"
@scroll="handleScroll">
<div
class="list-view-phantom"
:style="{
height: contentHeight
}">
</div>
<ul
ref="content"
class="list-view-content">
<li
class="list-view-item"
:style="{
height: itemHeight + 'px'
}"
v-for="(item, index) in visibleData"
:key="index">
{{ item }}
</li>
</ul>
</div>
</template>script:
<script>
export default {
name: 'ListView',
props: {
data: {
type: Array,
default: function() {
const list = []
for (let i = 0; i < 1000000; i++) {
list.push('列表' + i)
}
return list
}
},
height: {
type: Number,
default: 400
},
itemHeight: {
type: Number,
default: 30
},
},
computed: {
contentHeight() {
return this.data.length * this.itemHeight + 'px';
}
},
mounted() {
this.updateVisibleData();
},
data() {
return {
visibleData: []
};
},
methods: {
updateVisibleData(scrollTop) {
scrollTop = scrollTop || 0;
const visibleCount = Math.ceil(this.$el.clientHeight / this.itemHeight); // 取得可見區(qū)域的可見列表項數(shù)量
const start = Math.floor(scrollTop / this.itemHeight); // 取得可見區(qū)域的起始數(shù)據(jù)索引
const end = start + visibleCount; // 取得可見區(qū)域的結(jié)束數(shù)據(jù)索引
this.visibleData = this.data.slice(start, end); // 計算出可見區(qū)域?qū)臄?shù)據(jù),讓 Vue.js 更新
this.$refs.content.style.webkitTransform = `translate3d(0, ${ start * this.itemHeight }px, 0)`; // 把可見區(qū)域的 top 設置為起始元素在整個列表中的位置(使用 transform 是為了更好的性能)
},
handleScroll() {
const scrollTop = this.$el.scrollTop;
this.updateVisibleData(scrollTop);
}
}
}
</script>
css:
<style lang="scss" scoped>
.list-view {
overflow: auto;
position: relative;
border: 1px solid #aaa;
width: 200px;
}
.list-view-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list-view-content {
left: 0;
right: 0;
top: 0;
position: absolute;
}
.list-view-item {
padding: 5px;
color: #666;
line-height: 30px;
box-sizing: border-box;
}
</style>以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue最強table vxe-table 虛擬滾動列表 前端導出問題分析
最近遇到個問題,后臺一次性返回2萬條列表數(shù)據(jù)并且需求要求所有數(shù)據(jù)必須全部展示,不能做假分頁,怎么操作呢,下面通過本文介紹下vue最強table vxe-table 虛擬滾動列表 前端導出問題,感興趣的朋友一起看看吧2023-10-10
基于vue2.0+vuex的日期選擇組件功能實現(xiàn)
這篇文章主要介紹了 基于vue2.0+vuex的日期選擇組件功能實現(xiàn),詳細介紹了使用vue編寫的日期組件,,非常具有實用價值,需要的朋友可以參考下。2017-03-03

