Vue3的新特性

總概

1) 性能提升

  • 打包大小減少 41%
  • 初次渲染快 55%,更新渲染快 133%
  • 記憶體減少 54%
  • 使用 Proxy 代替 defineProperty 實現數據響應式
  • 重寫虛擬 DOM 的實現和 Tree-Shaking

2) 新增特性

  • Composition (組合) API
  • setup
    • ref 和 reactive
    • computed 和 watch
    • 新的生命周期函數
    • provide 與 inject
  • 新組件
    • Fragment – 文檔碎片
    • Teleport – 瞬移組件的位置
    • Suspense – 非同步載入組件的 loading 介面
  • 其它 API 更新
    • 全局 API 的修改
    • 將原來的全局 API 轉移到應用對象
    • 模板語法變化

詳解

1) setup

  • 新的 option,所有的組合 API 函數都在此使用,只在初始化時執行一次
  • 函數如果返回對象,對象中的屬性或方法,模板中可以直接使用

2) ref

  • 作用:定義一個數據的響應式
  • 語法:const xxx = ref(initValue):
    • 創建一個包含響應式數據的引用(reference)對象
    • js 中操作數據:xxx.value
    • 模板中操作數據:不需要.value
  • 一般用來定義一個基本類型的響應式數據

3) reactive

  • 作用: 定義多個數據的響應式
  • const proxy = reactive(obj): 接收一個普通對象然後返回該普通對象的響應式代理器對象
  • 響應式轉換是「深層的」:會影響對象內部所有嵌套的屬性
  • 內部基於 ES6 的 Proxy 實現,通過代理對象操作源對象內部數據都是響應式的

4) 比較 Vue2 與 Vue3 的響應式(重要)

vue2 的響應式

  • 核心:
    • 對象:通過 defineProperty 對對象的已有屬性值的讀取和修改進行劫持(監視/攔截)
    • 數組:通過重寫數組更新數組一系列更新元素的方法來實現元素修改的劫持
  • 問題:
    • 對象直接新添加的屬性或刪除已有屬性,介面不會自動更新
    • 直接通過下標替換元素或更新 length,介面不會自動更新 arr[1] = {}

Vue3 的響應式

  • 核心:
    • 通過 Proxy(代理):攔截對 data 任意屬性的任意(13 種)操作,包括屬性值的讀寫,屬性的添加,屬性的刪除等…
    • 通過 Reflect(反射):動態對被代理對象的相應屬性進行特定的操作
    • 文檔:

5) setup 細節

  • setup 執行的時機
    • 在 beforeCreate 之前執行(一次),此時組件對象還沒有創建
    • this 是 undefined,不能通過 this 來訪問 data/computed/methods / props
    • 其實所有的 composition API 相關回調函數中也都不可以
  • setup 的返回值
    • 一般都返回一個對象:為模板提供數據,也就是模板中可以直接使用此對象中的所有屬性/方法
    • 返回對象中的屬性會與 data 函數返回對象的屬性合併成為組件對象的屬性
    • 返回對象中的方法會與 methods 中的方法合併成功組件對象的方法
    • 如果有重名,setup 優先
    • 注意:
    • 一般不要混合使用:methods 中可以訪問 setup 提供的屬性和方法,但在 setup 方法中不能訪問 data 和 methods
    • setup 不能是一個 async 函數:因為返回值不再是 return 的對象,而是 promise,模板看不到 return 對象中的屬性數據
  • setup 的參數
    • setup(props,context) / setup(props,{attrs,slots,emit})
    • props:包含 props 配置聲明且傳入了的所有屬性的對象
    • attrs:包含沒有在 props 配置中聲明的屬性的對象,相當於 this.$attrs
    • slots:包含所有傳入的插槽內容的對象,相當於 this.$slots
    • emit:用來分發自定義事件的函數,相當於 this.$emit

6) reactive 與 ref-細節

  • 是 Vue3 的 composition API 中 2 個最重要的響應式 API
  • ref 用來處理基本類型數據,reactive 用來處理對象(遞歸深度響應式)
  • 如果用 ref 對象/數組,內部會自動將對象/數組轉換為 reactive 的代理對象
  • ref 內部:通過給 value 屬性添加 getter/setter 來實現對數據的劫持
  • reactive 內部:通過使用 Proxy 來實現對對象內部所有數據的劫持,並通過 Reflect 操作對象內部數據
  • ref 的數據操作:在 js 中要.value,在模板中不需要(內部解析模板時會自動添加.value)

7) 計算屬性與監視

  • computed 函數:
    • 與 computed 配置功能一致
    • 只有 getter
    • 有 getter 和 setter
  • watch 函數
    • 與 watch 配置功能一致
    • 監視指定的一個或多個響應式數據,一旦數據變化,就自動執行監視回調
    • 默認初始時不執行回調,但可以通過配置 immediate 為 true,來指定初始時立即執行第一次
    • 通過配置 deep 為 true,來指定深度監視
  • watchEffect 函數
    • 不用直接指定要監視的數據,回調函數中使用的哪些響應式數據就監視哪些響應式數據
    • 默認初始時就會執行第一次,從而可以收集需要監視的數據
    • 監視數據發生變化時回調

8) 生命周期

與 2.x 版本生命周期相對應的組合式 API

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

新增的鉤子函數

組合式 API 還提供了以下調試鉤子函數:

  • onRenderTracked
  • onRenderTriggered

09) 自定義 hook 函數

  • 使用 Vue3 的組合 API 封裝的可復用的功能函數
  • 自定義 hook 的作用類似於 vue2 中的 mixin 技術
  • 自定義 Hook 的優勢:很清楚復用功能程式碼的來源,更清楚易懂
  • 需求 1:收集用戶滑鼠點擊的頁面坐標
 1 import { ref, onMounted, onUnmounted } from 'vue' 
 2 /* 
 3 收集用戶滑鼠點擊的頁面坐標
 4 */ 
 5 export const useMousePosition=()=> {   
 6   // 初始化坐標數據   
 7   const x = ref(-1)
 8   const y = ref(-1)
 9 
10   // 用於收集點擊事件坐標的函數   
11   const updatePosition = (e: MouseEvent) => {
12     x.value = e.pageX
13     y.value = e.pageY
14   }
15 
16   // 掛載後綁定點擊監聽   
17   onMounted(() => {
18     document.addEventListener('click', updatePosition)
19   })
20 
21   // 卸載前解綁點擊監聽   
22   onUnmounted(() => {
23     document.removeEventListener('click', updatePosition)
24   })
25 
26   return { x, y }
27 }
28 
29 <template>
30   <div>
31       <h2>x: {{ x }}, y: {{ y }}</h2>
32   </div>
33 </template>
34 
35   <script>
36   import { ref,setup } from 'vue'
37 /* 在組件中引入並使用自定義hook
38   自定義hook的作用類似於vue2中的mixin技術
39   自定義Hook的優勢:很清楚復用功能程式碼的來源, 更清楚易懂*/
40   
41 import useMousePosition from './hooks/useMousePosition'
42 
43 export default {
44   const { x, y } = useMousePosition()
45   return {
46     x,
47     y 
48   }
49 } 
50   </script>
Tags: