Vue 的優化技巧

来源:https://www.cnblogs.com/operate/archive/2023/02/09/17104259.html
-Advertisement-
Play Games

演示代碼使用 Vue3 + ts + Vite 編寫,但是也會列出適用於 Vue2 的優化技巧,如果某個優化只適用於 Vue3 或者 Vue2,我會在標題中標出來。 代碼優化 v-for 中使用 key 使用 v-for 更新已經渲染的元素列表時,預設用就地復用策略;列表數據修改的時候,他會根據 k ...


演示代碼使用 Vue3 + ts + Vite 編寫,但是也會列出適用於 Vue2 的優化技巧,如果某個優化只適用於 Vue3 或者 Vue2,我會在標題中標出來。

代碼優化

v-for 中使用 key


使用 v-for 更新已經渲染的元素列表時,預設用就地復用策略;列表數據修改的時候,他會根據 key 值去判斷某個值是否修改,如果修改,則重新渲染這一項,否則復用之前的元素;

使用key的註意事項:

  • 不要使用可能重覆的或者可能變化 key 值(控制台也會給出提醒)
  • 如果數組中的數據有狀態需要維持時(例如輸入框),不要使用數組的 index 作為 key 值,因為如果在數組中插入或者移除一個元素時,其後面的元素 index 將會變化,這回讓vue進行原地復用時錯誤的綁定狀態。
  • 如果數組中沒有唯一的 key值可用,且數組更新時不是全量更新而是採用類似push,splice來插入或者移除數據時,可以考慮對其添加一個 key 欄位,值為 Symbol() 即可保證唯一。

何時使用何種key?

這是一個非常有考究的問題,首先你要知道 vue 中的 原地復用 (大概就是 虛擬dom 變化時,兩個 虛擬dom節點key 如果一樣就不會重新創建節點,而是修改原來的節點)。

當我們渲染的數據不需要保持狀態時,例如常見的單純的表格分頁渲染(不包含輸入,只是展示)、下拉載入更多等場景,那麼使用 index 作為 key 再好不過,因為進入下一頁或者上一頁時就會原地復用之前的節點,而不是重新創建,如果使用唯一的 id 作為 key 反而會重新創建dom,性能相對較低。

此外使用 index 作為 key 我還應該要儘量避免對數組的中間進行 增加/刪除 等會影響後面元素key變化的操作。這會讓 vue 認為後面所有元素都發生了變化,導致多餘的對比和原地復用。

所以使用 index 作為 key 需要滿足:

  1. 數據沒有獨立的狀態
  2. 數據不會進行 增加/刪除 等會影響後面元素key變化的操作

哪何時使用 id 作為 key 呢?

對於大多數數據的 id 都是唯一的,這無疑的一個 key 的優選答案。對於任何大多數情況使用 id 作為 key 都不會出現上面 bug。但是如果你需要考慮性能問題,那就就要思考是否應該使用原地復用了。

同樣是上面的分頁數據展示,如果使用 id 作為 key ,可想而知每一頁的每一條數據 id 都是不一樣的,所以當換頁時兩顆 虛擬DOM樹 的節點的 key 完全不一致,vue 就會移除原來的節點然後創建新的節點。可想而知效率會更加低下。但是他也有它的優點。唯一的 key 可以幫助 diff 更加精確的為我們綁定狀態,這尤其適合數據有獨立的狀態的場景,例如帶輸入框或者單選框的列表數據。

所以何時使用 id 作為 key?只有一點:

  1. 無法使用 index 作為 key 的時候

v-for 和 v-if 不要一起使用(Vue2)


此優化技巧僅限於Vue2,Vue3 中對 v-for 和 v-if 的優先順序做了調整

這個大家都知道

永遠不要把 v-ifv-for 同時用在同一個元素上。

原因是 v-for 的 優先順序高於 v-if,所以當它們使用再同一個標簽上是,每一個渲染都會先迴圈再進行條件判斷。

註意: Vue3 中 v-if 優先順序高於 v-for,所以當 v-forv-if 一起使用時效果類似於 Vue2 中把 v-if 上提的效果

例如下麵這段代碼在 Vue2 中是不被推薦的,Vue 也會給出對應的警告.

<ul>
  <li v-for="user in users" v-if="user.active">
    {{ user.name }}
  </li>
</ul>

我們應該儘量將 v-if 移動到上級或者使用計算屬性來處理數據.

<ul v-if="active">
  <li v-for="user in users">
    {{ user.name }}
  </li>
</ul>

如果你不想讓迴圈的內容多出一個無需有的上級容器,那麼你可以選擇使用 template 來作為其父元素,template 不會被瀏覽器渲染為 DOM 節點.

如果我想要判斷遍歷對象裡面每一項的內容來選擇渲染的數據的話,可以使用 computed 來對遍歷對象進行過濾.

// js
let usersActive = computed(()=>users.filter(user => user.active))

// template
<ul>
    <li v-for="user in usersActive">
      {{ user.name }}
    </li>
</ul>

合理的選擇 v-if 和 v-show


v-ifv-show 的區別相比大家都非常熟悉了;v-if 通過直接操作 DOM 的刪除和添加來控制元素的顯示和隱藏;v-show 是通過控制 DOMdisplay CSS熟悉來控制元素的顯示和隱藏.

由於對 DOM 的 添加/刪除 操作性能遠遠低於操作 DOM 的 CSS 屬性.

所以當元素需要頻繁的 顯示/隱藏 變化時,我們使用 v-show 來提高性能。

當元素不需要頻繁的 顯示/隱藏 變化時,我們通過 v-if 來移除 DOM 可以節約掉瀏覽器渲染這個的一部分DOM需要的資源.

使用簡單的計算屬性


應該把複雜計算屬性分割為儘可能多的更簡單的 property。

  • 易於測試
    當每個計算屬性都包含一個非常簡單且很少依賴的表達式時,撰寫測試以確保其正確工作就會更加容易。
  • 易於閱讀
    簡化計算屬性要求你為每一個值都起一個描述性的名稱,即便它不可復用。這使得其他開發者 (以及未來的你) 更容易專註在他們關心的代碼上並搞清楚發生了什麼。
  • 更好的“擁抱變化”
    任何能夠命名的值都可能用在視圖上。舉個例子,我們可能打算展示一個信息,告訴用戶他們存了多少錢;也可能打算計算稅費,但是可能會分開展現,而不是作為總價的一部分。
    小的、專註的計算屬性減少了信息使用時的假設性限制,所以需求變更時也用不著那麼多重構了。

computed 大家很熟悉, 它會在其表達式中依賴的響應式數據發送變化時重新計算。如果我們在一個計算屬性中書寫了比較複雜的表達式,那麼其依賴的響應式數據也任意變得更多。當其中任何一個依賴項變化時整個表達式都需要重新計算.

let price = computed(()=>{
  let basePrice = manufactureCost / (1 - profitMargin)
  return (
      basePrice -
      basePrice * (discountPercent || 0)
  )
})

當 manufactureCost、profitMargin、discountPercent 中任何一個變化時都會重新計算整個 price。

但是如果我們改成下麵這樣

let basePrice = computed(() => manufactureCost / (1 - profitMargin))
let discount = computed(() => basePrice * (discountPercent || 0))
let finalPrice = computed(() => basePrice - discount)

如果當 discountPercent 變化時,只會 重新計算 discount 和 finalPrice,由於 computed 的緩存特性,不會重新計算 basePrice.

functional 函數式組件(Vue2)


註意:這僅僅在 Vue2 中被作為一種優化手段,在 3.x 中,有狀態組件和函數式組件之間的性能差異已經大大減少,並且在大多數用例中是微不足道的。因此,在 SFC 上使用 functional 的開發人員的遷移路徑是刪除該 attribute,並將 props 的所有引用重命名為 $props,將 attrs 重命名為 $attrs

優化前:

<template>
    <div class="cell">
        <div v-if="value" class="on"></div>
        <section v-else class="off"></section>
    </div>
</template>

<script>
export default {
    props: ['value'],
}
</script>

優化後:

<template functional>
    <div class="cell">
        <div v-if="props.value" class="on"></div>
        <section v-else class="off"></section>
    </div>
</template>

<script>
export default {
    props: ['value'],
}
</script>
  • 沒有this(沒有實例)
  • 沒有響應式數據

拆分組件


什麼?你寫的一個vue文件有一千多行代碼?

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 這篇筆記用來收集在日常開發中所用到的安卓adb shell命令,參照了一些大佬的再加上我自己平時用到的整理在了一塊兒,感謝無私共用的大佬們。 將會持續更新,歡迎收藏~ 一、基本用法 命令語法 adb 命令的基本語法如下: adb [-d|-e|-s <serialNumber>] <comma ...
  • 隨著對用戶體驗要求的提高,產品要求提升用戶體驗,多端體驗一致。隨著多端相同的業務也越來越多,需要投入IOS,Android,Web多端開發人員。這就迫切的需要一種一次開發同時使用在Android ,IOS ,Web的解決方案。達到降本增效的目的。在幾個小業面嘗試,總結經驗後,我們採用react-na... ...
  • 源碼下載地址 https://github.com/Aizhuxueliang/springboot_shiro.git 前提你電腦的安裝好這些工具:jdk8、idea、maven、git、mysql; shiro的主要概念 Shiro是一個強大的簡單易用的Java安全框架,主要用來更便捷的認證、授 ...
  • 有多種實現方式: 一、使用 Set 對象: Array.from(new Set(array)) 該方法會先創建一個 Set 對象,然後再使用 Array.from 方法將 Set 對象轉換為數組,因為 Set 對象不允許有重覆的元素,所以這樣可以實現去重的效果。 但是,如果數組中的元素是對象,Se ...
  • Web一階段面試題 1.簡述 <!doctype> 的作用? <!DOCTYPE> 聲明叫做文檔類型定義(DTD),聲明的作用是為了告訴瀏覽器該文件的類型。讓瀏覽器解析器知道應該用哪個規範來解析文檔。 五大主流的瀏覽器及其內核? Chrome 內核 Blink Safari 內核 Webkit Op ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 項目效果 我們今天要實現的是一個路徑規劃的功能,有兩個輸入框。輸入起點終點,然後查詢,得到規劃的路徑,效果如下: 我們會用到以下庫: Axios:用於發送請求,請求高德地圖的地理編碼API Jquery:也用於發送請求 Cesium:地圖 ...
  • 上文創建了一堆 utils、component-info,並實現了新組件模塊相關目錄和文件的創建。本文繼續實現後面的內容。 1 組件樣式文件並導入 在 src/service 目錄中創建 init-scss.ts 文件,該文件導出 initScss 函數。 由於 .vue 類型的組件的樣式就直接寫在 ...
  • JavaScript 詞法環境 本文主要講解JS詞法環境,我們將看到什麼是詞法環境,詞法範圍如何工作,函數內部的名稱如何解析,內部屬性,弄清楚詞法環境利於我們理解閉包。讓我們開始吧... 什麼是詞法環境? 在理解閉包時,最大的混淆來源是術語“辭彙環境”,或者只是“辭彙”這個詞。在電腦科學中術語“詞 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...