天天看點

Vue3的新特性分析

總結:1.如何初始化vue3項目 2.支援多個根節點 3.入口檔案mian.js的改變4.更好的typescript支援 5.自動的tree-shaking 6.傳送門teleport 7. composition api 8.setup 9.ref 9.reactive 10.readonly 11.computed 12.watch 13.watchEffect 14.生命周期鈎子 15.依賴注入 16.refs 17.代碼組織 18.邏輯複用

方法一:通過vue-cli直接建立,要求腳手架的版本最新

方法二:在一個初始化的vue2項目中,在終端中使用指令vue add vue-next來更新為vue3項目。(注意是在一個初始化的vue2項目,不要瞎搞)

我們都知道在vue2中隻允許在template中定義一個根節點,否則會出現The template root requires exactly one element的提示報錯并導緻編譯錯誤。

在vue3中我們可以在template裡寫上多個根節點,這個特性在vue3中得以展現。

實作原理(DocumentFragment)可參考官網

我們先來看在vue2中main.js的代碼引入:

我們再來看在vue3中main.js的代碼引入:

vue3因為有着typescript的支援,配合vscode可以在編寫代碼中有着十分好的類型提示,開發體驗十分之好

在vue3中自動會對打包建構的代碼進行tree-shaking。對使用者來說不需要的vue功能不用打包進去了會優化最終的檔案體積;對架構開發者來說可以提供更多的功能也不用的擔心會導緻使用者的檔案體積變大(在使用者不使用該功能的情況下)

vue3新增了傳送門teleport的概念,我們來看一個業務場景(在vue2下),并使用vue3的傳送門來解決這個業務場景,官方的示範位址

在vue2中因為隻允許有一個根節點,代碼書寫如下:(注意在下方的代碼中根節點#app的style="position: relative;")

我們在子元件ModalButton中想要實作一個基于視窗居中的彈框,代碼書寫如下:(注意這裡的.modal的style="position: absolute;")

于是我們得到了基于根節點#app的居中彈框,這不是我們想要的結果,我們是想要基于視窗(這裡可以是body)的居中彈框啊!!!,效果圖如下:

Vue3的新特性分析

緊接着該請出我們vue3的新特性傳送門(teleport)了,下面是用vue3重寫在子元件ModalButton中的代碼,參考如下:

使用了傳送門 <teleport to="body"> </teleport>後的效果圖如下,我們實作了基于body的居中彈窗:

Vue3的新特性分析

我們需要注意使用 <teleport to="body"> </teleport>後在渲染的時候并不是渲染到目前引入這個元件的元件内而是渲染到指定的element内

我們還需要注意teleport是可以在一個頁面元件中使用多次的,但是我們在使用多個teleport時需要注意它們之間的z-index關系,這是一個添加的操作。

我們更需要注意如果我在teleport中加入子元件,此時這個子元件的父元件是誰呢?在傳送門内定義的子元件的父元件是屬于引入這個元件的元件,在這裡我在元件ModalButton中使用了teleport,如果這個teleport中還定義了子元件,那麼這個在teleport中定義的子元件的父元件是ModalButton!!!

Vue3的新特性分析

接着才是vue3的重頭戲,那就是composition api。這可以說是完全颠覆了使用vue的邏輯書寫習慣,為了不引入全新的概念,采用獨立的函數來建立和監聽響應式的狀态等

我們不必擔心在vue2的options api會不能在vue3中使用,它和vue3的composition api是相容共存的,但是建議統一風格的寫法。

接下來将composition api的每個api單獨做為一個大标題來書寫:

Vue3的新特性分析

setup是初始化的入口,代表着目前元件初始化composition api的入口,在setup函數中return的對象中的值可以直接寫在template中,但是注意如果不做任何處理,直接用傳回的值在template中書寫的話,這個值不是響應式資料!!!

我們來看一下setup入口的運用,代碼參考如下:

在setup函數中return的對象中的值可以直接寫在template中,注意這裡傳回的得是一個對象,如果你傳回一個函數的話,實際上是調用render函數傳回一個vnode.

因為在data内可以擷取到setup傳回的值,是以可以直接在template中使用這個傳回的值。

注意這裡的在setup函數中的this是擷取不到的,因為setup函數的執行比beforeCreate和created調用的時間都要早,它是在options api之前調用的,自然擷取不到

setup的第一個參數是props,(即setup(props){})可以擷取父元件傳遞過來的props,當然這個由父元件傳遞過來的props是不可以在子元件中修改的,是隻讀的屬性。

ref是響應式系統api的一員大将,在上方的例子中我們可以發現不做任何處理直接傳回的count不是響應式資料,它就是一個普通的值,可是我們的需求是在我點選按鈕的時候count可以做為響應式資料被累加

ref可以用于建立一個響應式資料,代碼參考如下:

注意點:這裡通過 const count1=ref(0)建立了一個值為0的響應式資料,并在handleClickCount1該方法中實作了對該響應式資料累加的方法。

我們需要注意這裡的是count1現在是一個RefImpl對象,0這個值被儲存在這個對象的value屬性下,是以我們在setup函數中需要通過count1.value來擷取這個值0,這令我們徒增了許多心智負擔。

雖然我們在setup函數中需要通過count1.value來擷取這個值0,但是我們可以直接傳回這個count1對象,并在template中直接使用{{count1}}來擷取這個值

ref是響應式系統api的一員大将,在上方的例子中我們通過ref建立一個響應式資料,我們還可以通過reactive來建立一個一個響應式資料,代碼參考如下:

注意點:這裡通過let user=reactive({name:'lth',age:20})建立一個引用類型的響應式資料,并在handleAge中實作了對user.age的累加.

我們需要注意這裡的user是Proxy對象,可以直接通過user.age和user.name來直接通路屬性值,這一點得和使用ref差別開來.

readonly是響應式系統api的一員大将,在上面的例子中我們使用了reactive建立一個響應式資料,我們可以看到在點選按鈕時,user.age的值會被累加,也就是說該user.age的值是可以被修改的,如果我們想要讓一個值即是響應式資料又是不可修改的隻讀的值呢?我們可以使用readonly,代碼參考如下:

我們可以回顧一下在vue2中父元件傳遞給子元件的props屬性也是響應式的,但是我們在子元件中是不能直接修改props資料的,它也是一個隻讀屬性.

在vue3中直接對在子元件中收到的props自動設定了readonly,如果你企圖在子元件中直接修改props屬性,是會報錯的,代碼如下:

computed是響應式系統api的一員大将,這裡的計算屬性接收一個對應的函數,我們回顧一個計算屬性,它是一個依賴别的屬性的屬性,通過傳回一個屬性供模闆調用

通過計算屬性建立的是也響應式資料,直接上代碼:

watch是響應式系統api的一員大将,watch的第一個參數必須是響應式資料或者是一個傳回一個響應式資料的函數.直接上代碼:

watchEffect是響應式系統api的一員大将,它不需要一開始設定去觀察誰,始終擷取書寫在改函數中的值的最新值,直接接收一個函數,并在一開始一上來就立即執行了一遍.代碼如下:

setup函數的執行比beforeCreate和created調用的時間都要早,它是在options api之前調用的,如下表就是生命周期鈎子的改變:

beforeCreate

使用 setup()

created

beforeMount

使用 onBeforeMount

mounted

使用onMounted

beforeUpdate

使用onBeforeUpdate

updated

使用onUpdated

beforeDestroy

使用onBeforeUnmount

destroyed

使用onUnmounted

errorCaptured

使用onErrorCaptured

依賴注入(provide/inject)可以用于元件通信,我們先來看在APP.vue中的代碼:

provide的第一個參數是key,第二個參數是value

我們再來看在子元件Bar中的代碼:

使用refs可以擷取真實dom元素或者元件執行個體,代碼參考如下:

Vue3的新特性分析

為什麼要去使用 composition api呢,因為可以更好的實作代碼組織,我們來看以往在vue2中書寫的正常代碼:

上面的代碼組織看起來比較備援,不同的邏輯點放在不同的地方,邏輯少的話比較清晰,但是邏輯多的話找起來麻煩,我們在來看換成composition api後的寫法(下面還不是最佳的寫法,最佳寫法在下下面)

上面的寫法中我們已經可以清晰的觀察到一個功能塊的使用,我們在來做些改變,按照功能把功能塊單獨抽離為一個函數,利用到了組合的思想,代碼如下:

我們可以清晰的看到上面的寫法帶來的簡便性,并且我們可以将上方的功能塊函數單獨放在一個js檔案内導出,在由主入口來引入這個導出的函數,這是最佳解,代碼如下:

我們知道一個函數其實就是代表着可以複用的,在vue2中我們想要複用元件往往會使用mixins來實作,代碼參考如下:

下面是在./MoveMixin.js的複用元件的邏輯代碼:

如果我們有多個複用元件需要被使用,使用mixins導緻來源不清晰和容易造成命名沖突的問題是十分棘手的,我們在來看vue3為我們帶來的在邏輯複用上的好處,代碼參考如下:

使用veu3的新特性封裝完複用元件的邏輯後,在元件中使用的代碼如下:

下面有一個坑,就是傳回的響應式資料如果直接解構,解構出來的值不再是響應式資料,可以使用toRefs來解決這個問題.

我們可以發現我們的邏輯複用是十分的清晰的.