Vue3-0 七大亮點是什麼??

作者:獵戶座小陳

juejin.cn/post/6967570296677236743

一,性能比 2.x 快 1.2~2 倍

diff 算法的優化

在 vue2 中,虛擬 dom 是全量比較的。

在 vue3 中,增加了靜態標記 PatchFlag。在創建 vnode 的時候,會根據 vnode 的內容是否可以變化,爲其添加靜態標記 PatchFlag。diff 的時候,只會比較有 PatchFlag 的節點。PatchFlag 是有類型的,比如一個可變化文本節點,會將其添加 PatchFlag 枚舉值爲 TEXT 的靜態標記。這樣在 diff 的時候,只需比對文本內容。需要比對的內容更少了。PatchFlag 還有動態 class、動態 style、動態屬性、動態 key 屬性等枚舉值。

render 階段的靜態提升(render 階段指生成虛擬 dom 樹的階段)

在 vue2 中,一旦檢查到數據變化,就會 re-render 組件,所有的 vnode 都會重新創建一遍,形成新的 vdom 樹。

在 vue3 中,對於不參與更新的 vnode,會做靜態提升,只會被創建一次,在 re-render 時直接複用。

靜態提升可以理解爲第一次 render 不參與更新的 vnode 節點的時候,保存它們的引用。re-render 新 vdom 樹時,直接拿它們的引用過來即可,無需重新創建。

事件偵聽緩存

在 vue2 中,我們寫的 @click="onClick" 也是被當作動態屬性,diff 的時候也要對比。但我們知道它不會變化,比如變成 @click="onClick2",綁定別的值。

在 vue3 中,如果事件是不會變化的,會將 onClick 緩存起來(跟靜態提升達到的效果類似),該節點也不會被標記上 PatchFlag(也就是無需更新的節點)。這樣在 render 和 diff 兩個階段,事件偵聽屬性都節約了不必要的性能消耗。

我曾經維護過一個擁有很龐大 dom 樹的頁面。由於節點非常多,無需參與更新的節點也很多,使用 vue2 的情況下,在 render 和 diff 兩個階段,消費了很多性能,如果當時有 vue3 的話,我想性能會被優化很多。

二,按需編譯,體積比 Vue2.x 更小(Tree shaking)

在 vue3 中,可以如下面這樣引用 vue 的功能函數,如果你的項目沒有用到 watch,那編譯時就會把 tree shaking 掉。

import { computed, watch, nextTick } from "vue";
複製代碼

利用的就是 ES6 模塊系統 import/export。

三,Compostion API: 組合 API / 注入 API

這裏要說到代碼的組織方式,傳統的網頁是 html/css/javascript(結構 / 樣式 / 邏輯)分離。vue/react 通過組件化的方式,將聯繫緊密的結構 / 樣式 / 邏輯放在一起,有利於代碼的維護。

compostion api 更進一步,着力於 JavaScript(邏輯)部分,將邏輯相關的代碼放在一起,近而有利於代碼的維護。

在 vue2 的組件內,使用的是 Option API 風格 (data/methods/mounted) 來組織的代碼,這樣會讓邏輯分散,舉個例子就是我們完成一個計數器功能,要在 data 裏聲明變量,在 methods 定義響應函數,在 mounted 裏初始化變量,如果在一個功能比較多、代碼量比較大的組件裏,你要維護這樣一個功能,就需要在 data/methods/mounted 反覆的切換到對應位置,然後進行代碼的更改。

在 vue3 中,使用 setup 函數。如下所示跟 count 相關的邏輯,都放到 counter.js 文件裏,跟 todo 相關的邏輯放到 todos.js 裏。

import useCounter from './counter'
import useTodo from './todos'

setup(){
  let { val, todos, addTodo } = useTodo()
  let {count,add} = useCounter() 
  return {
    val, todos, addTodo,
    count,add,
  }
}
複製代碼

在我看來這就是 Compostion API 最大的特點,以功能爲單位的代碼組織方式。同時它可以讓代碼更易重用。

說到重用,Compostion API 的方式也比 mixin 的方式好很多,你可以清楚的看到組件使用的數據和方法來自哪個模塊,而 mixin 進組件的功能,常常會讓我們困惑此功能來自哪個 mixin。

四,更好的 TS 支持

vue2 不適合使用 ts,原因在於 vue2 的 Option API 風格。options 是個簡單對象,而 ts 是一種類型系統、面向對象的語法。兩者有點不匹配。

在 vue2 結合 ts 的具體實踐中,要用 vue-class-component 強化 vue 組件,讓 Script 支持 TypeScript 裝飾器,用 vue-property-decorator 來增加更多結合 Vue 特性的裝飾器,最終搞的 ts 的組件寫法和 js 的組件寫法差別挺大。

在 vue3 中,量身打造了 defineComponent 函數,使組件在 ts 下,更好的利用參數類型推斷 。Composition API 代碼風格中,比較有代表性的 api 就是 ref 和 reactive,也很好的支持了類型聲明。

import { defineComponent, ref } from 'vue'
 
const Component = defineComponent({
    props: {
        success: { type: String },
        student: {
          type: Object as PropType<Student>,
          required: true
       }
    },
    setup() {
      const year = ref(2020)
      const month = ref<string | number>('9')
     
      month.value = 9 // OK
     const result = year.value.split('') // => Property 'split' does not exist on type 'number'
 }
複製代碼

五,自定義渲染 API(Custom Renderer API)

下面我們可以看到 vue2 和 vue3 的入口寫法有所不同

// vue2
import Vue from 'vue'
import App from './App.vue'
new Vue({ => h(App)}).$mount('#app')

// vue3
const { createApp }  from 'vue'
import App from "./src/App"
createApp(App).mount(('#app')
複製代碼

vue 官方實現的 createApp 會給我們的 template 映射生成 html 代碼,但是要是你不想渲染生成到 html ,而是要渲染生成到 canvas 之類的不是 html 的代碼的時候,那就需要用到 Custom Renderer API 來定義自己的 render 渲染生成函數了。

// 你自己實現一個createApp,比如是渲染到canvas的。
import { createApp } from "./runtime-render";
import App from "./src/App"; // 根組件

createApp(App).mount('#app');
複製代碼

六,更先進的組件

Fragment 組件

// vue2 是不允許這樣寫的,組件必須有一個跟節點,現在可以這樣寫,vue 將爲我們創建一個虛擬的 Fragment 節點。

<template>
  <div>Hello</div>
  <div>World</div>
</template>
複製代碼

這樣寫有何好處呢?一是如果根節點不是必要的,無需創建了,減少了節點數。二是 Fragment 節點是虛擬的,不會 DOM 樹中呈現。

Suspense 組件

<Suspense>
  <template >
    <Suspended-component />
  </template>
  <template #fallback>
    Loading...
  </template>
</Suspense>
複製代碼

在 Suspended-component 完全渲染之前,備用內容會被顯示出來。如果是異步組件,Suspense 可以等待組件被下載,或者在設置函數中執行一些異步操作。

七,更快的開發體驗(vite 開發構建工具)

在使用 webpack 作爲開發構建工具時,npm run dev 都要等一會,項目越大等的時間越長。熱重載頁有幾秒的延遲,但是如果用 vite 來做 vue3 的開發構建工具,npm run dev 秒開,熱重載也很快。這種開發體驗真是很爽,拒絕等待。

vite 的原理還是用了瀏覽器支持 import 關鍵字了,啓動項目不用 webpack 構建工具先構建了,瀏覽器直接請求路由對應的代碼文件,代理服務器針對單個文件進行編譯並返回。如果請求的文件裏還 import 了其他文件,同理瀏覽器繼續發請求,代理服務器返回。就這樣實現了 npm run dev 時無需編譯,實時請求實時編譯。

總結:

其他的,數據監聽方式變成了 Proxy,消除了 Object.defineProperty 現有的限制(例如無法檢測新的屬性添加),並提供更好的性能。

vue3 解決了 vue2 的一些問題,大型應用的性能問題、ts 支持不友好問題,自定義渲染 API 解決體系架構存在的問題,如果在 vue3 的基礎上實現 weex 框架會好很多。也做出了很多優化,Compostion API 讓代碼的組織形式更好。vite 開發構建工具讓開發體驗更好,Tree shaking 讓包更小、性能更優。

總的來說 vue3 還是非常棒的,帶來了很多非常好的新特性。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/p2k7rRCMlqvUr4u2xaeeaw