vxe-list?vue?如何實(shí)現(xiàn)下拉框的虛擬列表
vxe-list vue下拉框的虛擬列表
vxe-table vxe-list vue 實(shí)現(xiàn)下拉框的虛擬列表
虛擬列表的實(shí)現(xiàn)原理
只渲染可視區(qū)的 dom 節(jié)點(diǎn),其余不可見的數(shù)據(jù)卷起來,只會(huì)渲染可視區(qū)域的 dom 節(jié)點(diǎn),提高渲染性能及流暢性,優(yōu)點(diǎn)是支持海量數(shù)據(jù)的渲染;當(dāng)然也會(huì)有缺點(diǎn):滾動(dòng)效果相對(duì)略差(海量數(shù)據(jù)與滾動(dòng)效果的取舍問題就看自己的需求嘍);
<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: '選項(xiàng)'+i, value: i }) } this.list = list this.loading = false this.$nextTick(() => { this.$XModal.message({ message: `渲染 ${list.length} 行,用時(shí) ${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 毫秒左右
具體用法可以去看 官方文檔,在線運(yùn)行 http://jsrun.net/CW2Kp/edit
vue虛擬列表實(shí)現(xiàn)原理
應(yīng)用場景
前端的業(yè)務(wù)開發(fā)中會(huì)遇到不使用分頁方式來加載長列表的需求。如在數(shù)據(jù)長度大于 1000 條情況,DOM 元素的創(chuàng)建和渲染需要的時(shí)間成本很高,完整渲染列表所需要的時(shí)間不可接受,同時(shí)會(huì)存在滾動(dòng)時(shí)卡頓問題;
解決該卡頓問題的重點(diǎn)在于如何降低長列表DOM渲染成本問題,文章將介紹通過虛擬列表渲染的方式解決該問題。
為什么需要虛擬列表
虛擬列表是對(duì)長列表的一種優(yōu)化方案。在前端開發(fā)中,會(huì)碰到一些不能使用分頁方式來加載列表數(shù)據(jù)的業(yè)務(wù)形態(tài),我們稱這種列表叫做長列表。比如,手機(jī)端,淘寶商品展示,美團(tuán)外賣等,數(shù)據(jù)量特別龐大,不適合分頁,以及懶加載,這時(shí)候我們可以采用虛擬列表,只展示可視區(qū)域數(shù)據(jù)。
實(shí)現(xiàn)思路
虛擬列表的核心思想為可視區(qū)域渲染,在頁面滾動(dòng)時(shí)對(duì)數(shù)據(jù)進(jìn)行截取、復(fù)用DOM進(jìn)行展示的渲染方式。
實(shí)現(xiàn)虛擬列表就是處理滾動(dòng)條滾動(dòng)后的可見區(qū)域的變更,其中具體步驟如下:
1.計(jì)算當(dāng)前可見區(qū)域起始數(shù)據(jù)的 startIndex
2.計(jì)算當(dāng)前可見區(qū)域結(jié)束數(shù)據(jù)的 endIndex
3.計(jì)算當(dāng)前可見區(qū)域的數(shù)據(jù),并渲染到頁面中
4.計(jì)算 startIndex 對(duì)應(yīng)的數(shù)據(jù)在整個(gè)列表中的偏移位置 startOffset,并設(shè)置到列表上
基礎(chǔ)實(shí)現(xiàn)
我們首先要考慮的是虛擬列表的 HTML、CSS 如何實(shí)現(xiàn):
- 列表元素(.list-view)使用相對(duì)定位
- 使用一個(gè)不可見元素(.list-view-phantom)撐起這個(gè)列表,讓列表的滾動(dòng)條出現(xiàn)
- 列表的可見元素(.list-view-content)使用絕對(duì)定位,left、right、top 設(shè)置為 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ū)域的可見列表項(xiàng)數(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); // 計(jì)算出可見區(qū)域?qū)?yīng)的數(shù)據(jù),讓 Vue.js 更新 this.$refs.content.style.webkitTransform = `translate3d(0, ${ start * this.itemHeight }px, 0)`; // 把可見區(qū)域的 top 設(shè)置為起始元素在整個(gè)列表中的位置(使用 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>
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue使用Google地圖的實(shí)現(xiàn)示例代碼
這篇文章主要介紹了vue使用Google地圖的實(shí)現(xiàn)示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12vue項(xiàng)目的屏幕自適應(yīng)多個(gè)方案總結(jié)
最近在用VUE寫大屏頁面,遇到屏幕自適應(yīng)問題,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目的屏幕自適應(yīng)多個(gè)方案的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06vue最強(qiáng)table vxe-table 虛擬滾動(dòng)列表 前端導(dǎo)出問題分析
最近遇到個(gè)問題,后臺(tái)一次性返回2萬條列表數(shù)據(jù)并且需求要求所有數(shù)據(jù)必須全部展示,不能做假分頁,怎么操作呢,下面通過本文介紹下vue最強(qiáng)table vxe-table 虛擬滾動(dòng)列表 前端導(dǎo)出問題,感興趣的朋友一起看看吧2023-10-10關(guān)于vue.js彈窗組件的知識(shí)點(diǎn)總結(jié)
最近在開發(fā)過程對(duì)對(duì)于組件化的開發(fā)有一些感想,于是開始記錄下這些。彈窗組件一直是 web 開發(fā)中必備的,使用頻率相當(dāng)高,最常見的莫過于 alert,confirm和prompt這些,不同的組件庫對(duì)于彈窗的處理也是不一樣的,下面來一起看看吧。2016-09-09vue開發(fā)設(shè)計(jì)分支切換與cleanup實(shí)例詳解
這篇文章主要為大家介紹了vue開發(fā)設(shè)計(jì)分支切換與cleanup實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Vite圖片資源打包優(yōu)化的實(shí)現(xiàn)
本文主要介紹了Vite圖片資源打包優(yōu)化的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04基于vue2.0+vuex的日期選擇組件功能實(shí)現(xiàn)
這篇文章主要介紹了 基于vue2.0+vuex的日期選擇組件功能實(shí)現(xiàn),詳細(xì)介紹了使用vue編寫的日期組件,,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-03-03