在開始之前,我應該先了解你 - 聊聊vue 3的改動

最近準備用 Vue3 開發新的專案了,趁這個機會順便整理 vue3 與 vue2 有哪些差異, 稍微瀏覽一下新功能和寫法 ,不得不說真的覺得跟 React 好像 XD,當然也有人覺得我幹嘛不學 react 就好了,但花點時間寫過一些 vue3 的練習之後,確實感受到 vue3 參考了不少 React 的優點,但學習曲線更加友善,效能方面也提昇了不少,好 vue3,不學嗎?

以下列舉幾項 vue3 和 vue2 的差異

setup

執行階段會在 beforeCreate 之前,取代了原本得 beforeCreate 和 created,可以想像成是唯一的入口 function,會在這裡初始化 data 宣告 ref 等等..

同時也發現 methods 不見了,所有需要用到的 function 都直接宣告在 setup 裡面即可,跟以往不同的是,用到甚麼功能就要記得從 vue 引入

reactive ({})

reactive 可以傳入一個物件或是陣列,但如果傳入 number,string 等基礎型別就會報錯,因為 Proxy 只接受 object 型別的資料,透過 reactive 才能響應式的偵測資料的變動,所以以往寫在 data 的東西就會改寫在這裡囉!

Lifecycle Hooks

熟悉的 mounted、beforeDestroy…不見了,取而代之的是皆以 on 開頭的 Hooks(onMounted、onBeforeUnmount),並且要記得將生命週期要寫在 setup 函式裡面。

下面附上一張生命週期對照表

emit&props

正當我習慣地寫下

1
this.$emit("changePage", 5);

發現我熟悉的 this 不見了!?居然變成了 undefined,所以我說那個 this 呢?稍微翻了一下文件,發現在 setup 裡面已經取不到 this 了,取而代之的是 context,setup 可以傳入兩個參數,props 和 context

直接 console.log context 看看結果

所以我們可以透過 context 取得 attrs、 slots 、emit 等屬性

因此使用 emit 可以有兩種方式

  1. 透過解構賦值
  2. 透過 context 呼叫

另外,props 不需要 return 出去 ,就可以直接在 template 使用了

以往我們可以在 props 定義類型 、預設值等等,現在 emit 也可以像 props 一樣列舉有哪些 emit,同時也能針對傳進來的參數做初步的判斷。

Fragments

在 vue2 如果 template 的最外層沒有一個根結點的話就會報錯

The template root requires exactly one element vue/valid-template-root

vue3 終於可以擺脫這個束縛啦!

::v-deep

以往的 deep(scss) 或是>>>(css) 改用::v-deep 取代了

甚麼時候會用到? 當你的 css 需要改動到下一層 component 的樣式

::v-global

終於可以在 style scoped 裡面,寫下全域的樣式了

ref

只能監聽 String 、Number、 Boolean 的變化,當 Array、 Object 內部屬性有變化是沒有辦法監聽的(請用 reactive)

在 setup 裡面 ref 會回傳一個物件,所以必須用 value 屬性來取到值,而在 template 裡 ref 會自動 unwraps 就可以直接取用,不需要.value

假如是要取得 DOM 的話

  1. 先在 setup 定義一個 ref
  2. 綁定在想要取得的 DOM 上
  3. 就可以在 onMounted 階段取得 DOM

toRef

將物件中的屬性變成響應式的數據,但要注意不會觸發畫面的更新,toRef 接收兩個參數 ,第一個對象, 第二個是屬性


如果想要把一個物件的每個屬性都變成響應式的資料,就可以用 toRefs

watch、watchEffect

watch 第一個參數為要監控的值 ,第二個參數傳入 callback function 可以取得新舊值的變化

watchEffect 只要傳入 callback 函式, 在初始化的時候就會先執行一遍 ,會自動監聽在函式裡有用到的值變化

Teleport

想必大家都曾經遇過一個問題 ,假設有 A 、B 兩個 component(B 為 A 的子 component)想要在 B 控制一個彈窗顯示, 就會有層級的問題(z-index) ,無法讓 B 的 z-index 大於 A component, 因此無法達到彈窗的滿板覆蓋效果, 透過 Teleport 我們可以先在自己的 component 定義好內容,並且控制顯示與否,然後渲染到外層的 DOM 上,就像任意門一樣,以後寫彈窗又更方便了

Index.vue

App.vue

Suspense

利用 defineAsyncComponent 來動態載入 component ,在還沒載入前,會先看到 template#fallback 裡面的內容 ,等到 component 載入完畢之後就會顯示#default 的內容。

transition-class

算是把 class 名稱定義的更明確

createApp

vue 的初始化從 new Vue()改成用 createApp

vue2

vue3

定義全域的變數

被移除的項目

  • $on, $off ,$once
    是的,意謂著我們要跟 event bus 說再見了
  • keyCode

在 vue3 裡面使用

1
<input v-on:keyup.13="submit" />

會出現了這段錯誤

KeyboardEvent.keyCode’ modifier on ‘v-on’ directive is deprecated. Using ‘KeyboardEvent.key’ instead

打開 MDN 才發現 KeyboardEvent.keyCode 居然已經變成 deprecated 了!

以上只是很簡略的列出一些差異,要深入了解的話還是建議閱讀官方文件

對了,如果要用 Vue CLI 開發 vue3,記得要先升級 Vue CLI 版本到 4 以上,或是可以搭配 vite 開發

參考資料: https://v3.vuejs.org/

更新於 2022/6

如果以上述的方式寫過一陣子的 vue3 應該都會有一個感想

要一直 return 變數和 function 真的好麻煩阿…

於是就有了<script setup>這個語法糖誕生,也就是把 setup 直接寫在 script 後面,跟以往不同的是 script 會寫在最上面,接著是 template,最後是 style,重點是…

再也不用 return 了! 超級方便!

defineProps() & defineEmits()

不過改用 script setup 寫法你可能會有一個疑問: 那 props 和 emit 我要從哪裡取得呢? 就靠defineProps & defineEmits 了!

這邊要特別注意defineProps & defineEmits都不需要自行引入,因為官網有提到

defineProps and defineEmits are compiler macros only usable inside <script setup>. They do not need to be imported and are compiled away when <script setup> is processed.

必須說用過 script setup 之後就回不去了,程式碼變得更加簡潔 ,可以少寫很多程式碼,推薦大家有時間可以試試看,更多 script setup 介紹可參考這裡