vue性能优化小结
組件優化
一般來說,你不需要太關心vue的運行時性能,它在運行時非常快,但付出的代價是初始化時相對較慢。先看一下常見的vue寫法:在html里放一個app組件,app組件里又引用了其他的子組件,形成一棵以app為根節點的組件樹。
<div id="app"><router-view></router-view></div> 復制代碼而正是這種做法引發了性能問題,要初始化一個父組件,必然需要先初始化它的子組件,而子組件又有它自己的子組件。那么要初始化根標簽,就需要從底層開始冒泡,將頁面所有組件都初始化完。所以我們的頁面會在所有組件都初始化完才開始顯示。
這個結果顯然不是我們要的,更好的結果是頁面可以從上到下按順序流式渲染,這樣可能總體時間增長了,但首屏時間縮減,在用戶看來,頁面打開速度就更快了。
異步組件
new Vue({components: {A: { /*component-config*/ },B (resolve) {setTimeout(() => {resolve({ /*component-config*/ })}, 0);}} }) 復制代碼或者是
const Foo = resolve => {// require.ensure 是 Webpack 的特殊語法,用來設置 code-split point// (代碼分塊)require.ensure(['./Foo.vue'], () => {resolve(require('./Foo.vue'))}) } const Foo = resolve => require(['./Foo.vue'], resolve) const router = new VueRouter({routes: [{ path: '/foo', component: Foo }] }) 復制代碼把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,從而實現路由懶加載
把組件按組分塊
有時候我們想把某個路由下的所有組件都打包在同個異步 chunk 中。只需要 給 chunk 命名,提供 require.ensure 第三個參數作為 chunk 的名稱:
const Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo') const Bar = r => require.ensure([], () => r(require('./Bar.vue')), 'group-foo') const Baz = r => require.ensure([], () => r(require('./Baz.vue')), 'group-foo') 復制代碼利用v-if和terminal
<head><!--some component --><div v-if="showB"><!--some component --></div><div v-if="showC"><!--some component --></div> </head>data: {showB: false,showC: false},created () {// 顯示BsetTimeout(() => {this.showB = true;}, 0);// 顯示CsetTimeout(() => {this.showC = true;}, 0);} 復制代碼這個示例寫起來略顯啰嗦,但它已經實現了我們想要的順序渲染的效果。頁面會在組件初始化完后顯示,然后再按順序渲染其余的組件,整個頁面渲染方式看起來是流式的。
有些人可能會擔心v-if存在一個編譯/卸載過程,會有性能影響。但這里并不需要擔心,因為v-if是惰性的,只有當第一次值為true時才會開始初始化。
組件keep-alive
如果你做用一個大型web的spa的時候,你有很多router,對應的是很多個頁面。在頁面的快速切換中(如常見的tab頁),為了保證頁面加載的效率,除了緩存機制之外,vue的keep-alive組件可以幫的上忙。它會把組件保存在瀏覽器內存當中,方便你快速切換。
基礎優化
v-if v-show
權限問題,只要涉及到權限相關的展示無疑要用 v-if,沒有權限限制下根據用戶點擊的頻次選擇,頻繁切換的使用 v-show,不頻繁切換的使用 v-if,這里要說的優化點在于減少頁面中 dom 總數,我比較傾向于使用 v-if,因為減少了 dom 數量,加快首屏渲染。 不要在模板里面寫過多的表達式與判斷 v-if="isShow && isAdmin && (a || b)",這種表達式雖說可以識別,但是不是長久之計,當看著不舒服時,適當的寫到 methods 和 computed 里面封裝成一個方法,這樣的好處是方便我們在多處判斷相同的表達式,其他權限相同的元素再判斷展示的時候調用同一個方法即可。
循環盡可能在使用 v-for 時提供 key,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴默認行為以獲取性能上的提升。引用vue文檔:當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用“就地復用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單復用此處每個元素,并且確保它在特定索引下顯示已被渲染過的每個元素。這個類似 Vue 1.x 的 track-by="$index" 。
這個默認的模式是高效的,但是只適用于不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。
為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key 屬性。理想的 key 值是每項都有的唯一 id。 watch 和 computed 用哪個的問題看官網的例子,計算屬性主要是做一層 filter 轉換,切忌加一些調用方法進去,watch 的作用就是監聽數據變化去改變數據或觸發事件如 this.$store.dispatch('update', { ... }) 數據請求在哪個時候盡量根據需求考慮后,多多利用promise的并發請求。
其他
如打包優化:在打包時可將一些靜態模塊排除,如ue、vuex、vue-router、axios 等,換用國內的 bootcdn 直接引入到根目錄的 index.html 中。在 webpack 里有個 externals,可以忽略不需要打包的庫
externals: {'vue': 'Vue','vue-router': 'VueRouter','vuex': 'Vuex','axios': 'axios' } 復制代碼或者是利用webpack的動態鏈接庫DllPlugin,打包會輸出一個類dll包(dll包源于windows的動態鏈接庫),這些代碼本身不會執行,主要是提供給我們的業務代碼引用。將靜態資源文件(運行依賴包)與源文件分開打包,先使用DllPlugin給靜態資源打包,再使用DllReferencePlugin讓源文件引用資源文件。dll在打包一次后即可,下次業務代碼修改也不會重新打包,然后在html里分模塊引入
<script src="./static/js/vendor.dll.js"></script><script src="/dist/build.js"></script> 復制代碼關于webpack的使用建議閱讀《深入淺出webpack》一書。 其他的還有樣式優化、減少組件耦合性等。
轉載于:https://juejin.im/post/5c179dcc51882521eb44a3b4
總結
- 上一篇: vue 表单验证按钮事件交由父组件触发
- 下一篇: python 数字格式化