溫馨提示×

溫馨提示×

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

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

vue虛擬滾動性能優(yōu)化的方法

發(fā)布時間:2022-08-10 10:55:36 來源:億速云 閱讀:194 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細介紹“vue虛擬滾動性能優(yōu)化的方法”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當(dāng),希望這篇“vue虛擬滾動性能優(yōu)化的方法”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

    引言

    一個簡單的情景模擬(千萬別被帶入):

    A: 假設(shè)現(xiàn)在有 10 萬條數(shù)據(jù),你作為前端該怎么優(yōu)化這種大數(shù)據(jù)的列表?

    B: 針對大數(shù)據(jù)列表一般不會依次性加載,會采用上拉加載、分頁加載等方式實現(xiàn)優(yōu)化.

    A: 那假如加載到最后一條數(shù)據(jù)的時候,頁面上只是列表部分的數(shù)據(jù)就至少對應(yīng) 10 萬個 dom 節(jié)點,你覺得一個頁面渲染至少 10 萬個 dom 節(jié)點的性能如何?

    A: 如果這樣的列表有 n 個呢?還有沒有別的優(yōu)化方式?

    B: 要不我把自己優(yōu)化一下 ......

    其實解決上述問題就可以使用 虛擬滾動 來實現(xiàn)優(yōu)化,相信大家對這個詞都不陌生,但由于這個名詞比較短(又是虛擬,又是滾動)導(dǎo)致很多人覺得這是非常高大上、難以理解的內(nèi)容,但其實恰恰相反。

    本文的目的就是幫助你以 最簡單 的方式 理解虛擬滾動,甚至實現(xiàn) 虛擬滾動.

    虛擬滾動(Virtual Scrolling)

    理解虛擬滾動

    其實要理解 虛擬滾動 這個詞很簡單,按照 虛擬 和 滾動 兩部分來理解就很簡單了,下面就一一拆解。

    虛擬

    通常在頁面列表中,要渲染的 列表數(shù)量 和真實在文檔中存在的 DOM 節(jié)點數(shù) 是 1 : 1 的。

    每個列表項都擁有相同的高度(假設(shè)是 30px),這個列表容器中需要完全渲染的列表數(shù)(假設(shè)是 100 條)和在頁面中的高度是一致的,即此時的高度就為 100 * 30 = 300 px,對應(yīng)列表的 DOM 數(shù)量為 100,如:

    vue虛擬滾動性能優(yōu)化的方法

    對于 虛擬滾動 來講,虛擬 的意思是指實際要渲染完整列表對應(yīng)的高度是通過 虛擬計算 的,并不是指文檔中存在對應(yīng)的 DOM 節(jié)點數(shù)。

    上面的栗子對應(yīng)到虛擬滾動來講,就意味著實際渲染完整列表對應(yīng)的高度就仍為 100 * 30 = 300px,但實際渲染數(shù)就變?yōu)?10 條,關(guān)系圖大致如下:

    vue虛擬滾動性能優(yōu)化的方法

    滾動

    所謂 滾動 就很好理解了,因為列表可視區(qū)通常會限制一定的高度,即 列表可視區(qū)高度,那么此時只要 虛擬列表高度 值大于 列表可視區(qū)高度 時,就會產(chǎn)生滾動條即可發(fā)生滾動操作。

    值得注意的是,在發(fā)生滾動時需要對 實際渲染的列表 進行一些處理,否則會出現(xiàn) 實際渲染的列表 和 虛擬列表區(qū) 脫離的情況,比如:

    vue虛擬滾動性能優(yōu)化的方法

    關(guān)鍵點就是實現(xiàn)在發(fā)生 滾動 操作時,保證 實際渲染的列表 一直存在 列表可視區(qū) 中,并且動態(tài)切換需要渲染的列表數(shù)據(jù)。

    實現(xiàn)虛擬滾動

    核心步驟
    • 設(shè)置列表可視區(qū)的高度 containerHeight

    • 設(shè)置單個列表項的高度 listItemHeight

    • 計算渲染完整列表需要的高度 virtualHeight,即 virtualHeight = listItemHeight * data.length

    • 設(shè)置真實渲染數(shù)據(jù)的起始索引 startIndex、endIndex,用于從列表數(shù)據(jù) data 中獲取對應(yīng)的數(shù)據(jù)內(nèi)容

    • 注冊/監(jiān)聽滾動事件 onScroll

      • 獲取當(dāng)前實際滾動距離 eleScrollTop

      • 將 eleScrollTop 作為 translateY 的值,即 實際渲染列表元素 平移的數(shù)值,保證 實際渲染列表元素 一直存在可視區(qū)中

      • 根據(jù)實際的滾動距離 eleScrollTop,動態(tài)計算列表新的起始索引 startIndex、endIndex

    效果預(yù)覽

    vue虛擬滾動性能優(yōu)化的方法

    具體實現(xiàn)細節(jié)都在如下的代碼中,可結(jié)合其中的注釋閱讀:

    // App.vue
    <script>
    const list = (num = 10)=> {
      const data = [];
      for (let i = 0; i < num; i++) {
        data.push({
          id: i+1,
          name: `第 ${i+1} 條列表`
        });
      }
      return data;
    }
    </script>
    <template>
      <VirtualScroll :data="list(100)" />
    </template>
    // VirtualScroll.vue
    <template>
      <!-- 虛擬滾動內(nèi)容 -->
      <div
        class="virtual-scroller"
        @scroll="onScroll"
        :
      >
        <!-- 實際渲染的列表內(nèi)容 -->
        <ul
          class="real-list-content"
          :
        >
          <li
            v-for="item in visibleList"
            :key="item.id"
            :style="{
              height: `${listItemHeight}px`,
              'line-height': `${listItemHeight}px`,
            }"
          >
            <div>{{ item.name }}</div>
          </li>
        </ul>
        <!-- 虛擬列表元素 -->
        <div class="virtual-height" :>
          ~ 數(shù)據(jù)加載完畢 ~
        </div>
      </div>
    </template>
    <script>
    export default {
      name: "vue-virtual-scroll",
    };
    </script>
    <script setup language="ts">
    import { computed, ref } from "vue";
    const props = defineProps({
      data: {
        type: Array,
        default: [],
      },
      startIndex: {
        type: Number,
        default: 0,
      },
      endIndex: {
        type: Number,
        default: 10,
      },
      listItemHeight: {
        type: Number,
        default: 60,
      },
      containerHeight: {
        type: Number,
        default: 500,
      },
    });
    let { data, listItemHeight } = props;
    const tranlateY = ref(0); // 平移距離
    const startIndex = ref(props.startIndex); // 開始索引
    const endIndex = ref(props.endIndex); // 結(jié)束索引
    // 實際渲染的數(shù)據(jù)
    const visibleList = computed(() => {
      return data.slice(startIndex.value, endIndex.value);
    });
    // 虛擬滾動的高度
    const virtualHeight = computed(() => {
      return (data.length - visibleList.value.length) * listItemHeight + listItemHeight;
    });
    // 滾動事件
    const onScroll = (e) => {
      const eleScrollTop = e.target.scrollTop;
      // 保證實際渲染列表一直停留在可視區(qū)
      tranlateY.value = eleScrollTop;
      // 根據(jù)實際的滾動距離,動態(tài)計算列表開始索引
      startIndex.value = Math.floor(eleScrollTop / listItemHeight);
      // 基于開始索引
      endIndex.value = startIndex.value + 10;
    };
    </script>
    <style scoped>
    .virtual-scroller {
      border: solid 1px #eee;
      margin-top: 10px;
      height: 600px;
      overflow: auto;
    }
    .virtual-height {
      background: red;
      display: flex;
      align-items: end;
      justify-content: center;
      color: #fff;
    }
    ul {
      list-style: none;
      padding: 0;
      margin: 0;
    }
    li {
      outline: solid 1px #fff;
      background-color: #000;
      color: #fff;
    }
    </style>

    讀到這里,這篇“vue虛擬滾動性能優(yōu)化的方法”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

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

    vue
    AI