Vue中的性能優(yōu)化方案
最近使用 Vue 開發(fā)的過程中使用到一些對于性能有所提升的編碼方式,所以特別梳理出來,可以作為后續(xù) Vue 開發(fā)的編碼規(guī)范使用
性能優(yōu)化方案主要分為三類,下面就詳細講講這三類優(yōu)化方案的應(yīng)用
- 減少響應(yīng)式使用
- 減少 DOM 渲染
- 減少打包體積
減少響應(yīng)式使用
Vue 中使用最方便的就是響應(yīng)式的變量,在讀?。╣et)對象屬性的時候收集副作用函數(shù)(effect)依賴,在寫入(set)屬性時取出副作用函數(shù)依賴執(zhí)行,但是收集依賴、觸發(fā)依賴執(zhí)行畢竟都會影響到性能,所以在明確知道不需要使用響應(yīng)式變量的場景下,就應(yīng)該減少響應(yīng)式變量的使用
1. 使用 computed 緩存計算結(jié)果
computed 和普通方法的區(qū)別在于:computed 會緩存計算結(jié)果,只有當計算的內(nèi)容改變的時候才會重新計算,而普通方法每次都會重新計算。所以對于有計算邏輯的取值,建議盡量都通過 computed 來封裝一層
比如下面這個示例就是簡單的將 props 通過 computed 封裝一層后共 template 使用
const getTooltipStyle = computed((): CSSProperties => {
return {
color: props.color,
fontSize: props.fontSize,
};
});
2. 本地化響應(yīng)式變量
根據(jù) Vue 響應(yīng)式變量的原理,每次訪問響應(yīng)式數(shù)據(jù)時,都會收集依賴,所以在需要頻繁使用響應(yīng)式變量的時候,可以先將響應(yīng)式變量用一個本地變量存儲,轉(zhuǎn)換為一個非響應(yīng)式的變量
在 Vue3 中可以使用 unref 這個 api 來獲取到響應(yīng)式變量參數(shù)本身(Vue2 中直接通過 this 賦值就好)
const tableData = ref([])
const unrefTableData = unref(tableData) // 本地化變量后再做大量操作
unrefTableData.forEach(item => {
// 具體操作
})
3. 函數(shù)式組件(Vue2)
函數(shù)式組件是指:只接受一些 prop 參數(shù),無響應(yīng)式數(shù)據(jù),無實例的組件,主要應(yīng)用在創(chuàng)建簡單的展示組件,比如標題 header、純展示的表單等等。因為沒有響應(yīng)式數(shù)據(jù)和實例,所以初始化速度比普通有狀態(tài)的組件快很多,并且還支持返回多個節(jié)點
在 Vue2 中聲明函數(shù)式組件的方式如下
<!-- template 中的聲明方式 -->
<template functional>
</template>
<!-- jsx 中的聲明方式 -->
Vue.component("list", {
functional: true,
})
但是在 Vue3 中,有狀態(tài)的組件性能已經(jīng)大大提升,和無狀態(tài)組件(函數(shù)式組件)幾乎沒有差異,并且有狀態(tài)組件也支持了返回多個節(jié)點,所以官方也移除了 functional 定義函數(shù)式組件的方式,注意 Vue3 中是不兼容 Vue2 的函數(shù)式組件定義,所以如果未來打算升級 Vue3 的小伙伴就不建議使用函數(shù)式組件了
減少 DOM 渲染壓力
1. DOM 頻繁切換展示的情況使用 v-show
這是一個老身長談的優(yōu)化方案了,原理在于 v-if 和 v-show 實現(xiàn)方式的區(qū)別,對于 v-if 在不符合條件的情況下不會渲染 DOM 節(jié)點,對于 v-show 則是將各個條件情況都渲染出來,在通過 display: block / none 進行切換,所以在頻繁切換 DOM 展示情況的場景下,使用 v-show 的性能會相對更好,比如一個可編輯單元格需要頻繁切換編輯和保存后的狀態(tài)的時候
但 v-show 也不是沒有缺點,因為會把各個分支情況都提前渲染出來,如果節(jié)點很多并且不需要頻繁切換狀態(tài),用 v-if 會是更好的選擇
2. keep-alive 緩存組件狀態(tài)
在 Vue 中切換組件時,組件內(nèi)部的狀態(tài)也會丟失,比如我們在填寫一個表單的時候,切換到另外一個組件填寫其他信息,在切換回之前的表單組件后,原來填寫的信息會被刷新掉,這種情況下就會使用到 keep-alive 組件緩存組件狀態(tài)
比較常用的做法是在 <router-view> 標簽內(nèi)嵌套一層 <transition> 標簽增加組件切換時的過渡動畫效果,再嵌套一層 <keep-alive> 標簽緩存組件狀態(tài),最后使用 <component> 渲染動態(tài)組件或者元素
<router-view>
<template #default="{ Component, route }">
<transition>
<keep-alive>
<component :is="Component" :key="route.path" />
</keep-alive>
</transition>
</template>
</router-view>
3. 路由懶加載
我們都知道 Vue 是單頁面頁面應(yīng)用,如果在首屏加載的時候就把所有需要使用的路由都加載出來的話,那就太浪費性能了,所以使用懶加載的方式加載路由,減少首屏加載的壓力,才是更合理的方案
在 vue-router 中使用路由懶加載需要通過箭頭函數(shù)返回一個 import 組件的路徑,這樣在運行到這個組件的時候,才會運行 import 編譯加載組件
const form: AppRouteRecordRaw = {
path: "/basicForm",
name: "BasicForm",
component: () => import("/@/views/form/index.vue"),
meta: {
title: "基礎(chǔ)表單",
},
};
export default form;
4. 圖片懶加載
圖片使用懶加載的原因和路由懶加載類似,都是為了減少不必要的渲染。比如我們有一張很長的頁面有很多數(shù)據(jù)或者圖片需要展示,而顯示屏幕的可視高度卻是固定的,所以在屏幕高度外的內(nèi)容完全可以等到頁面需要的時候再加載,從而減少了可是屏幕區(qū)域內(nèi)的渲染壓力
圖片懶加載的原理是:判斷圖片出現(xiàn)在當前窗口時,將 data-src 替換為 src 加載圖片,比較常用三個可視區(qū)域判斷方式是
img.getBoundingClientRect().top<document.documentElement.clientHeight(元素相對于窗口位置 < 窗體高度)IntersectionObserverapi,當其監(jiān)聽到目標元素的可見部分到達屏幕高度內(nèi),執(zhí)行指定的回調(diào)函數(shù)loading="lazy"屬性(目前兼容性不是特別好,參考Lazy loading - Web 性能)
在 Vue 中使用圖片懶加載推薦使用 vue-lazyload 這個插件,直接通過 v-lazy 這個指令就可以實現(xiàn)圖片懶加載的效果
<ul>
<li v-for="img in list">
<img v-lazy="img.src" >
</li>
</ul>
5. 組件銷毀時要清除定時器、EventListener
有時我們會在項目中開啟 setTimeout 來定時觸發(fā)一些事件,比如定時提醒表單保存之類的需求,如果在離開組件時沒有及時清除掉定時器或者是 EventListener ,很多頁面堆積起來很容易造成頁面卡頓和內(nèi)存泄漏
常見的方案是在離開組件之前的 onBeforeUnmount 生命周期鉤子中清除掉定時器和 EventListener
onBeforeUnmount(() => {
try {
instance?.destroy?.();
} catch (error) {
instanceRef.value = null;
}
})
在清除 EventListener 要注意:移除相同的函數(shù)。以下第一種情況不能清理掉 click 事件,因為它們是不同的函數(shù)對象,需要使用第二種指向相同函數(shù)對象的方式清除
// 這種情況不生效,因為指向的是不同函數(shù)對象
input.addEventListener("click", () => console.log("Hello"))
input.removeEventListener("click", () => console.log("Hello"))
// 此時指向相同的函數(shù)對象才能清理掉 EventListener 事件
function handler() {
console.log("Hello")
}
input.addEventListener("click", () => handler)
input.removeEventListener("click", () => handler)
6. 列表使用唯一 key
這個主要是和 diff 算法的效率有關(guān),所以我也把它作為減少 DOM 渲染壓力的一個方案。在我們使用 v-for 循環(huán)渲染內(nèi)容的時候,需要為每個組件分配一個 id,這樣在組件內(nèi)容有更新的時候,diff 算法通過 id 能夠更高效的找到變化的節(jié)點,讓 dom 渲染更迅速。同時需要注意分配的 id 最好不是數(shù)組的 index,因為一旦增加或減少數(shù)組元素,index 也會發(fā)生變化,這樣就失去 id 的效果了
<template v-for="schema in getSchema" :key="schema.field">
<form-item
:schema="schema"
:form-props="getProps"
:all-default-values="defaultValueRef"
/>
</template>
減少打包體積
1. 開啟 gzip 壓縮
gzip 一種文件壓縮的格式,比較適合文本文件的壓縮,通常會縮小兩倍以上的體積,所以用在代碼文件的壓縮上非常合適
我們現(xiàn)在使用的打包工具還是 webpack,在 webpack 中開啟 gzip 打包的話可以使用 compression-webpack-plugin 這個插件,具體配置如下
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {
configureWebpack : {
plugins: [
new CompressionPlugin({
test: /\.(js|css|json|html)&/,
tereshold: 10 * 1024, // 超過 10 k 才壓縮
})
]
}
}
開啟 gzip 除了要在代碼中增加配置外,還需要服務(wù)端的支持,在前端中比較常用的是 Nginx,在 Nginx 中開啟 gzip 壓縮的主要配置參數(shù)如下
#開啟和關(guān)閉gzip模式 gzip on; #gizp壓縮起點,文件大于10k才進行壓縮 gzip_min_length 10k; # gzip 壓縮級別,1-9,數(shù)字越大壓縮的越好,也越占用CPU時間,一般為 5,再大效果就不明顯了 gzip_comp_level 5; # 進行壓縮的文件類型。 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ; #nginx對于靜態(tài)文件的處理模塊,開啟后會尋找以.gz結(jié)尾的文件,直接返回,不會占用cpu進行壓縮,如果找不到則不進行壓縮 gzip_static on # 是否在http header中添加Vary: Accept-Encoding,建議開啟 gzip_vary on; # 設(shè)置壓縮所需要的緩沖區(qū)大小,以4k為單位,如果文件為7k則申請2*4k的緩沖區(qū) gzip_buffers 2 4k; # 設(shè)置gzip壓縮針對的HTTP協(xié)議版本 gzip_http_version 1.1;
2. 按需引入第三方組件
我們平時使用的 UI 組件一般都是大而全的,我們的項目中很少會全部使用到,所以按需引入第三方組件,能夠有效減少應(yīng)用包體積
以我們現(xiàn)在使用的 Element Plus 組件為例,使用 unplugin-vue-components 和 unplugin-auto-import 這兩個插件來實現(xiàn)(參考官方教程)
首先引入兩個插件
pnpm i -D unplugin-vue-components unplugin-auto-import
然后再 Webpack 配置兩個插件即可
// webpack.config.js
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
// ...
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}到此這篇關(guān)于Vue中的性能優(yōu)化方案的文章就介紹到這了,更多相關(guān)Vue 性能優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用vue2實現(xiàn)帶地區(qū)編號和名稱的省市縣三級聯(lián)動效果
我們知道省市區(qū)縣都有名稱和對應(yīng)的數(shù)字唯一編號,使用編號可以更方便查詢以及程序處理,我們今天來了解一下使用vue2來實現(xiàn)常見的省市區(qū)下拉聯(lián)動選擇效果,需要的朋友可以參考下2018-11-11
vue2和vue3部署到服務(wù)器子目錄為空白頁問題及解決
這篇文章主要介紹了vue2和vue3部署到服務(wù)器子目錄為空白頁問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
vue中el-date-picker限制選擇7天內(nèi)&禁止內(nèi)框選擇
項目中需要選擇時間范圍,并且只能選擇當前日期之后的七天,本文就來介紹了vue中el-date-picker限制選擇7天內(nèi)&禁止內(nèi)框選擇,具有一定的參考價值,感興趣的可以了解一下2023-12-12
vite?vue3?規(guī)范化與Git?Hooks詳解
這篇文章主要介紹了vite?vue3?規(guī)范化與Git?Hooks,本文重點討論?git?提交規(guī)范,結(jié)合示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-10-10
在Vue3中使用provide和inject進行依賴注入的代碼詳解
在現(xiàn)代前端開發(fā)中,Vue.js已經(jīng)成為了非常流行的框架之一,它提供了極大的靈活性和可維護性,今天我們要探討的是Vue?3中的provide和inject功能,這是一種用于在組件樹中進行依賴注入的方法,需要的朋友可以參考下2024-06-06
Vue處理循環(huán)數(shù)據(jù)流程示例精講
這篇文章主要介紹了Vue處理循環(huán)數(shù)據(jù)流程,這個又是一個編程語言,?模版語法里面必不可少的一個,?也是使用業(yè)務(wù)場景使用最多的一個環(huán)節(jié)。所以學(xué)會使用循環(huán)也是重中之重了2023-04-04
讓axios發(fā)送表單請求形式的鍵值對post數(shù)據(jù)的實例
今天小編就為大家分享一篇讓axios發(fā)送表單請求形式的鍵值對post數(shù)據(jù)的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08

