欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue虛擬滾動性能優(yōu)化方式詳解

 更新時間:2022年08月10日 09:02:07   作者:熊的貓  
這篇文章主要為大家介紹了vue虛擬滾動性能優(yōu)化方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

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

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,如:

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

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

滾動

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

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

關(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
    • 獲取當前實際滾動距離 eleScrollTop
    • 將 eleScrollTop 作為 translateY 的值,即 實際渲染列表元素 平移的數(shù)值,保證 實際渲染列表元素 一直存在可視區(qū)中
    • 根據(jù)實際的滾動距離 eleScrollTop,動態(tài)計算列表新的起始索引 startIndex、endIndex

效果預(yù)覽

具體實現(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"
    :style="{ height: containerHeight + 'px' }"
  >
    <!-- 實際渲染的列表內(nèi)容 -->
    <ul
      class="real-list-content"
      :style="{ transform: `translateY(${tranlateY}px)` }"
    >
      <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" :style="{ height: virtualHeight + 'px' }">
      ~ 數(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>

最后

其實 虛擬滾動 并不難理解,就像 CSS 中的 BFC、JavaScript 中的閉包 等概念一樣,最初了解時你很難給它一個定義,但是實際上下功夫去了解它,其實也就那么一回事。

以上的實現(xiàn)方式是極簡的方式,沒有做任何的優(yōu)化、沒有考慮額外的場景,因為本文的目的還是想通過最簡單的實現(xiàn)去解釋虛擬滾動到底是怎么一回事,因此不必過于糾結(jié),當然在 vue 中早已有了相關(guān)庫的實現(xiàn) vue-virtual-scroller 可自行了解,更多關(guān)于vue虛擬滾動性能優(yōu)化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 不依任何賴第三方,單純用vue實現(xiàn)Tree 樹形控件的案例

    不依任何賴第三方,單純用vue實現(xiàn)Tree 樹形控件的案例

    這篇文章主要介紹了不依任何賴第三方,單純用vue實現(xiàn)Tree 樹形控件的案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • vue.js實現(xiàn)備忘錄demo

    vue.js實現(xiàn)備忘錄demo

    這篇文章主要為大家詳細介紹了vue.js實現(xiàn)備忘錄的相關(guān)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • vue項目打包后請求地址錯誤/打包后跨域操作

    vue項目打包后請求地址錯誤/打包后跨域操作

    這篇文章主要介紹了vue項目打包后請求地址錯誤/打包后跨域操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • vue2封裝webSocket的實現(xiàn)(開箱即用)

    vue2封裝webSocket的實現(xiàn)(開箱即用)

    在Vue2中,可以使用WebSocket實時通信,本文主要介紹了vue2封裝webSocket的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • vue的table表格組件的封裝方式

    vue的table表格組件的封裝方式

    這篇文章主要介紹了vue的table表格組件的封裝方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 解決vue2中使用elementUi打包報錯的問題

    解決vue2中使用elementUi打包報錯的問題

    這篇文章主要介紹了解決vue2中使用elementUi打包報錯的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 如何防止Vue組件重復(fù)渲染的方法示例

    如何防止Vue組件重復(fù)渲染的方法示例

    在 Vue.js 中,組件的重復(fù)渲染是一個常見的問題,可能會影響應(yīng)用的性能和用戶體驗,為了提升應(yīng)用的性能,開發(fā)者需要理解 Vue 的渲染機制,并應(yīng)用有效的方法來避免不必要的組件重渲染,本文將深入探討如何防止 Vue 組件重復(fù)渲染,并提供相關(guān)示例代碼,需要的朋友可以參考下
    2024-10-10
  • 詳解vue-cli 構(gòu)建項目 vue-cli請求后臺接口 vue-cli使用axios、sass、swiper

    詳解vue-cli 構(gòu)建項目 vue-cli請求后臺接口 vue-cli使用axios、sass、swiper

    本文通過實例代碼給大家詳細介紹了vue-cli 構(gòu)建項目 vue-cli請求后臺接口 vue-cli使用axios、sass、swiper的相關(guān)知識,需要的朋友可以參考下
    2018-05-05
  • Vue2?Observer實例dep和閉包中dep區(qū)別詳解

    Vue2?Observer實例dep和閉包中dep區(qū)別詳解

    這篇文章主要為大家介紹了Vue2?Observer實例dep和閉包中dep區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • vue+elementUI下拉框回顯問題及解決方式

    vue+elementUI下拉框回顯問題及解決方式

    這篇文章主要介紹了vue+elementUI下拉框回顯問題及解決方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02

最新評論