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

Joe Chang
Coding Hot Pot
Published in
8 min readJan 25, 2021

--

photo by @etienneblg

最近準備用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、beforeDestory…不見了,取而代之的是皆以on開頭的Hooks(onMounted、onBeforeUnmount),並且要記得將生命週期要寫在setup 函式裡面。

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

引用自vue官方文件

emit&props

正當我習慣地寫下

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裡面使用

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了! 超級方便!

不用return ref和函式,template就可以直接使用

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介紹可參考這裡

--

--

Joe Chang
Coding Hot Pot

前端工程師,唯有非常努力,才能看起來毫不費力