溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

vxe-list?vue怎么實(shí)現(xiàn)下拉框的虛擬列表

發(fā)布時(shí)間:2022-06-06 09:30:39 來源:億速云 閱讀:252 作者:zzz 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“vxe-list vue怎么實(shí)現(xiàn)下拉框的虛擬列表”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“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;
}

vxe-list?vue怎么實(shí)現(xiàn)下拉框的虛擬列表

接下來測(cè)試一下

渲染 1w 條只需要 150 毫秒左右

渲染 5w 條只需要 300 毫秒左右

渲染 10w 條只需要 500 毫秒左右

vue虛擬列表實(shí)現(xiàn)原理

應(yīng)用場(chǎng)景

前端的業(yè)務(wù)開發(fā)中會(huì)遇到不使用分頁方式來加載長(zhǎng)列表的需求。如在數(shù)據(jù)長(zhǎng)度大于 1000 條情況,DOM 元素的創(chuàng)建和渲染需要的時(shí)間成本很高,完整渲染列表所需要的時(shí)間不可接受,同時(shí)會(huì)存在滾動(dòng)時(shí)卡頓問題;

解決該卡頓問題的重點(diǎn)在于如何降低長(zhǎng)列表DOM渲染成本問題,文章將介紹通過虛擬列表渲染的方式解決該問題。 

為什么需要虛擬列表

虛擬列表是對(duì)長(zhǎng)列表的一種優(yōu)化方案。在前端開發(fā)中,會(huì)碰到一些不能使用分頁方式來加載列表數(shù)據(jù)的業(yè)務(wù)形態(tài),我們稱這種列表叫做長(zhǎng)列表。比如,手機(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è)置到列表上

vxe-list?vue怎么實(shí)現(xiàn)下拉框的虛擬列表

基礎(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>

到此,相信大家對(duì)“vxe-list vue怎么實(shí)現(xiàn)下拉框的虛擬列表”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI