亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

22個Vue優(yōu)化技巧(項目實用)

 更新時間:2021年09月13日 08:59:33   作者:月夕  
演示代碼使用 Vue3 + ts + Vite 編寫,但是也會列出適用于 Vue2 的優(yōu)化技巧,具有一定的參考價值,感興趣的小伙伴們可以參考一下

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

代碼優(yōu)化

v-for 中使用 key

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

使用key的注意事項:

  • 不要使用可能重復的或者可能變化 key 值(控制臺也會給出提醒)
  • 不要使用數(shù)組的 index 作為 key 值,因為如果在數(shù)組中插入一個元素時,其后面的元素 index 將會變化。
  • 如果數(shù)組中沒有唯一的 key 值可用,可以考慮對其添加一個 key 字段,值為 Symbol() 即可保證唯一。

v-if/v-else-if/v-else 中使用 key

可能很多人都會忽略這個點

原因:默認情況下,Vue 會盡可能高效的更新 DOM。這意味著其在相同類型的元素之間切換時,會修補已存在的元素,而不是將舊的元素移除然后在同一位置添加一個新元素。如果本不相同的元素被識別為相同,則會出現(xiàn)意料之外的副作用。

如果只有一個 v-if ,沒有 v-else 或者 v-if-else的話,就沒有必要加 key 了

相對于 v-for 的 key, v-if/v-else-if/v-else 中的 key 相對簡單,我們可以直接寫入固定的字符串或者數(shù)組即可

  <transition>
    <button 
      v-if="isEditing"
      v-on:click="isEditing = false"
    >
      Save
    </button>
    <button 
      v-else 
      v-on:click="isEditing = true"
    >
      Edit
    </button>
  </transition>
.v-enter-active, .v-leave-active {
  transition: all 1s;
}
.v-enter, .v-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
.v-leave-active {
  position: absolute;
}

例如對于上面的代碼, 你會發(fā)現(xiàn)雖然對 button 添加了 過渡效果, 但是如果不添加 key 切換時是無法觸發(fā)過渡的
v-for 和 v-if 不要一起使用(Vue2)

此優(yōu)化技巧僅限于Vue2,Vue3 中對 v-for 和 v-if 的優(yōu)先級做了調(diào)整

這個大家都知道

永遠不要把 v-if 和 v-for 同時用在同一個元素上。 引至 Vue2.x風格指南

原因是 v-for 的 優(yōu)先級高于 v-if,所以當它們使用再同一個標簽上是,每一個渲染都會先循環(huán)再進行條件判斷

注意: Vue3 中 v-if 優(yōu)先級高于 v-for,所以當 v-for 和 v-if 一起使用時效果類似于 Vue2 中把 v-if 上提的效果

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

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

我們應該盡量將 v-if 移動到上級 或者 使用 計算屬性來處理數(shù)據(jù)

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

如果你不想讓循環(huán)的內(nèi)容多出一個無需有的上級容器,那么你可以選擇使用 template 來作為其父元素,template 不會被瀏覽器渲染為 DOM 節(jié)點
如果我想要判斷遍歷對象里面每一項的內(nèi)容來選擇渲染的數(shù)據(jù)的話,可以使用 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-if 和 v-show 的區(qū)別相比大家都非常熟悉了; v-if 通過直接操作 DOM 的刪除和添加來控制元素的顯示和隱藏;v-show 是通過控制 DOM 的 display CSS熟悉來控制元素的顯示和隱藏
由于對 DOM 的 添加/刪除 操作性能遠遠低于操作 DOM 的 CSS 屬性
所以當元素需要頻繁的 顯示/隱藏 變化時,我們使用 v-show 來提高性能。
當元素不需要頻繁的 顯示/隱藏 變化時,我們通過 v-if 來移除 DOM 可以節(jié)約掉瀏覽器渲染這個的一部分DOM需要的資源

使用簡單的 計算屬性

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

易于測試
當每個計算屬性都包含一個非常簡單且很少依賴的表達式時,撰寫測試以確保其正確工作就會更加容易。

易于閱讀
簡化計算屬性要求你為每一個值都起一個描述性的名稱,即便它不可復用。這使得其他開發(fā)者 (以及未來的你) 更容易專注在他們關(guān)心的代碼上并搞清楚發(fā)生了什么。

更好的“擁抱變化”
任何能夠命名的值都可能用在視圖上。舉個例子,我們可能打算展示一個信息,告訴用戶他們存了多少錢;也可能打算計算稅費,但是可能會分開展現(xiàn),而不是作為總價的一部分。
小的、專注的計算屬性減少了信息使用時的假設性限制,所以需求變更時也用不著那么多重構(gòu)了。

引至 Vue2風格指南

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

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 函數(shù)式組件(Vue2)

注意,這僅僅在 Vue2 中被作為一種優(yōu)化手段,在 3.x 中,有狀態(tài)組件和函數(shù)式組件之間的性能差異已經(jīng)大大減少,并且在大多數(shù)用例中是微不足道的。因此,在 SFCs 上使用 functional 的開發(fā)人員的遷移路徑是刪除該 attribute,并將 props 的所有引用重命名為 $props,將 attrs 重命名為 $attrs。

優(yōu)化前

<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>

優(yōu)化后

<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(沒有實例)
  • 沒有響應式數(shù)據(jù)

拆分組件

什么?你寫的一個vue文件有一千多行代碼?🤔
合理的拆分組件不僅僅可以優(yōu)化性能,還能夠讓代碼更清晰可讀。單一功能原則嘛

源自 https://slides.com/akryum/vueconfus-2019#/4/0/3

優(yōu)化前

<template>
  <div :style="{ opacity: number / 300 }">
    <div>{{ heavy() }}</div>
  </div>
</template>

<script>
export default {
  props: ['number'],
  methods: {
    heavy () { /* HEAVY TASK */ }
  }
}
</script>

優(yōu)化后

<template>
  <div :style="{ opacity: number / 300 }">
    <ChildComp/>
  </div>
</template>

<script>
export default {
  props: ['number'],
  components: {
    ChildComp: {
      methods: {
        heavy () { /* HEAVY TASK */ }
      },
      render (h) {
        return h('div', this.heavy())
      }
    }
  }
}
</script>

由于 Vue 的更新是組件粒度的,雖然每一幀都通過數(shù)據(jù)修改導致了父組件的重新渲染,但是 ChildComp 卻不會重新渲染,因為它的內(nèi)部也沒有任何響應式數(shù)據(jù)的變化。所以優(yōu)化后的組件不會在每次渲染都執(zhí)行耗時任務

使用局部變量

優(yōu)化前

<template>
  <div :style="{ opacity: start / 300 }">{{ result }}</div>
</template>

<script>
import { heavy } from '@/utils'

export default {
  props: ['start'],
  computed: {
    base () { return 42 },
    result () {
      let result = this.start
      for (let i = 0; i < 1000; i++) {
        result += heavy(this.base)
      }
      return result
    }
  }
}
</script>

優(yōu)化后

<template>
  <div :style="{ opacity: start / 300 }">
    {{ result }}</div>
</template>

<script>
import { heavy } from '@/utils'

export default {
  props: ['start'],
  computed: {
    base () { return 42 },
    result () {
      const base = this.base
      let result = this.start
      for (let i = 0; i < 1000; i++) {
        result += heavy(base)
      }
      return result
    }
  }
}
</script>

這里主要是優(yōu)化前后的組件的計算屬性 result 的實現(xiàn)差異,優(yōu)化前的組件多次在計算過程中訪問 this.base,而優(yōu)化后的組件會在計算前先用局部變量 base,緩存 this.base,后面直接訪問 base。

那么為啥這個差異會造成性能上的差異呢,原因是你每次訪問 this.base 的時候,由于 this.base 是一個響應式對象,所以會觸發(fā)它的 getter,進而會執(zhí)行依賴收集相關(guān)邏輯代碼。類似的邏輯執(zhí)行多了,像示例這樣,幾百次循環(huán)更新幾百個組件,每個組件觸發(fā) computed 重新計算,然后又多次執(zhí)行依賴收集相關(guān)邏輯,性能自然就下降了。

從需求上來說,this.base 執(zhí)行一次依賴收集就夠了,把它的 getter 求值結(jié)果返回給局部變量 base,后續(xù)再次訪問 base 的時候就不會觸發(fā) getter,也不會走依賴收集的邏輯了,性能自然就得到了提升。

引至 揭秘 Vue.js 九個性能優(yōu)化技巧

使用 KeepAlive

在一些渲染成本比較高的組件需要被經(jīng)常切換時,可以使用 keep-alive 來緩存這個組件
而在使用 keep-alive 后,被 keep-alive 包裹的組件在經(jīng)過第一次渲染后,的 vnode 以及 DOM 都會被緩存起來,然后再下一次再次渲染該組件的時候,直接從緩存中拿到對應的 vnode 和 DOM,然后渲染,并不需要再走一次組件初始化,render 和 patch 等一系列流程,減少了 script 的執(zhí)行時間,性能更好。

注意: 濫用 keep-alive 只會讓你的應用變得更加卡頓,因為他會長期占用較大的內(nèi)存

事件的銷毀

當一個組件被銷毀時,我們應該清除組件中添加的 全局事件 和 定時器 等來防止內(nèi)存泄漏
Vue3 的 HOOK 可以讓我們將事件的聲明和銷毀寫在一起,更加可讀

function scrollFun(){ /* ... */}
document.addEventListener("scroll", scrollFun)

onBeforeUnmount(()=>{
  document.removeEventListener("scroll", scrollFun)
})

Vue2 依然可以通過 $once 來做到這樣的效果,當然你也可以在 optionsAPI beforeDestroy 中銷毀事件,但是我更加推薦前者的寫法,因為后者會讓相同功能的代碼更分散

function scrollFun(){ /* ... */}
document.addEventListener("scroll", scrollFun)

this.$once('hook:beforeDestroy', ()=>{
  document.removeEventListener("scroll", scrollFun)
})

function scrollFun(){ /* ... */}

export default {
  created() {
    document.addEventListener("scroll", scrollFun)
  },
  beforeDestroy(){
    document.removeEventListener("scroll", scrollFun)
  }
}

圖片加載

圖片懶加載:適用于頁面上有較多圖片且并不是所有圖片都在一屏中展示的情況,vue-lazyload 插件給我們提供了一個很方便的圖片懶加載指令 v-lazy

但是并不是所有圖片都適合使用懶加載,例如 banner、相冊等 更加推薦使用圖片預加載技術(shù),將當前展示圖片的前一張和后一張優(yōu)先下載。

采用合理的數(shù)據(jù)處理算法

這個相對比較考驗 數(shù)據(jù)結(jié)構(gòu)和算法 的功底
例如一個將數(shù)組轉(zhuǎn)化為多級結(jié)構(gòu)的方法

/**
 * 數(shù)組轉(zhuǎn)樹形結(jié)構(gòu),時間復雜度O(n)
 * @param list 數(shù)組
 * @param idKey 元素id鍵
 * @param parIdKey 元素父id鍵
 * @param parId 第一級根節(jié)點的父id值
 * @return {[]}
 */
function listToTree (list,idKey,parIdKey,parId) {
    let map = {};
    let result = [];
    let len = list.length;

    // 構(gòu)建map
    for (let i = 0; i < len; i++) {
        //將數(shù)組中數(shù)據(jù)轉(zhuǎn)為鍵值對結(jié)構(gòu) (這里的數(shù)組和obj會相互引用,這是算法實現(xiàn)的重點)
        map[list[i][idKey]] = list[i];
    }

    // 構(gòu)建樹形數(shù)組
    for(let i=0; i < len; i++) {
        let itemParId = list[i][parIdKey];
        // 頂級節(jié)點
        if(itemParId === parId) {
            result.push(list[i]);
            continue;
        }
        // 孤兒節(jié)點,舍棄(不存在其父節(jié)點)
        if(!map[itemParId]){
            continue;
        }
        // 將當前節(jié)點插入到父節(jié)點的children中(由于是引用數(shù)據(jù)類型,obj中對于節(jié)點變化,result中對應節(jié)點會跟著變化)
        if(map[itemParId].children) {
            map[itemParId].children.push(list[i]);
        } else {
            map[itemParId].children = [list[i]];
        }
    }
    return result;
}

其他

除了上面說的方法以外還有很多優(yōu)化技巧,只是我在項目并不是太常用🤣

  • 凍結(jié)對象(避免不需要響應式的數(shù)據(jù)變成響應式)
  • 長列表渲染-分批渲染
  • 長列表渲染-動態(tài)渲染(vue-virtual-scroller
  • ...

首屏/體積優(yōu)化

我在項目中關(guān)于首屏優(yōu)化主要有以下幾個優(yōu)化方向

  • 體積
  • 代碼分割
  • 網(wǎng)絡

體積優(yōu)化

  • 壓縮打包代碼: webpack 和 vite 的生產(chǎn)環(huán)境打包默認就會壓縮你的代碼,這個一般不需要特殊處理,webpack 也可以通過對應的壓縮插件手動實現(xiàn)
  • 取消 source-map: 可以查看你的打包產(chǎn)物中是否有 .map 文件,如果有你可以將 source-map 的值設置為false或者空來關(guān)閉代碼映射(這個占用的體積是真的大)
  • 打包啟用 gizp 壓縮: 這個需要服務器也開啟允許 gizp 傳輸,不然啟用了也沒啥用( webpack 有對應的 gzip 壓縮插件,不太版本的 webpack 壓縮插件可能不同,建議先到官網(wǎng)查詢)

代碼分割

代碼分割的作用的將打包產(chǎn)物分割為一個一個的小產(chǎn)物,其依賴 esModule。所以當你使用 import() 函數(shù)來導入一個文件或者依賴,那么這個文件或者依賴就會被單獨打包為一個小產(chǎn)物。 路由懶加載 和 異步組件 都是使用這個原理。

  • 路由懶加載
  • 異步組件

對于 UI庫 我一般不會使用按需加載組件,而是比較喜歡 CDN 引入的方式來優(yōu)化。

網(wǎng)絡

  • CDN: 首先就是上面的說的 CDN 引入把,開發(fā)階段使用本地庫,通過配置 外部擴展(Externals) 打包時來排除這些依賴。然后在 html 文件中通過 CDN 的方式來引入它們
  • Server Push: HTTP2已經(jīng)相對成熟了;經(jīng)過上面的 CDN 引入,我們可以對網(wǎng)站使用 HTTP2 的 Server Push 功能來讓瀏覽器提前加載 這些 CDN 和 其他文件。
  • 開啟 gzip: 這個上面已經(jīng)說過了,其原理就是當客戶端和服務端都支持 gzip 傳輸時,服務端會優(yōu)先發(fā)送經(jīng)過 gzip 壓縮過的文件,然后客戶端接收到在進行解壓。
  • 開啟緩存: 一般我使用的是協(xié)商緩存,但是這并不適用于所有情況,例如對于使用了 Server Push 的文件,就不能隨意的修改其文件名。所以我一般還會將生產(chǎn)的主要文件固定文件名

到此這篇關(guān)于22個Vue優(yōu)化技巧(項目實用)的文章就介紹到這了,更多相關(guān)Vue優(yōu)化技巧內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論