Vue3 已經發布一段時間了,這個版本從底層實現到上層 API 設計都發生了非常大的變化,但具體改變了些什么呢?一起簡單盤點下:
一、Composition API
使用傳統的option配置方法寫組件的時候問題,隨著業務復雜度越來越高,代碼量會不斷的加大;由于相關業務的代碼需要遵循option的配置寫到特定的區域,導致后續維護非常的復雜,同時代碼可復用性不高,而composition-api就是為了解決這個問題而生。
「1.1 Options API 的問題」
使用傳統OptionsAPI時,新增或者修改一個需求,就需要分別在data,methods,computed里修改 。當業務邏輯和功能越來越多的時候理解和維護復雜組件變得困難。

「1.2 Composition API 的優勢」
而Vue3 的組合式 API 將每個功能點抽成一個function使我們可以更加優雅的組織我們的代碼。讓相關功能的代碼更加有序的組織在一起。

「1.3 reactive對比ref」
在 vue2.x 中,數據都是定義在data
中。但是 Vue3.x 可以使用reactive
和ref
來進行數據定義。那么ref和reactive他們有什么區別呢?
從原理角度對比:
ref用來創建一個包含響應式的數據的引用對象
接收數據可以是:基本數據類型、對象類型
基本類型的數據:響應式依然是靠object.defineProperty()的get與set完成的
對象類型:內部求助vue3.0中一個新函數reactive函數通過proxy實現

源碼地址:https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/ref.ts
reactive用來定義:對象和數組通過使用Proxy來實現響應式(數據劫持), 并通過Reflect操作源對象內部的數據。
從使用角度對比:
ref定義的數據:操作數據需要
.value
,讀取數據時模板中不需要.value
直接使用即可。
reactive定義的數據:操作數據與讀取數據:均不需要
.value
。
1.4 新增 watchEffect
函數
watch
函數需要指明監視的屬性,并在回調函數中執行。默認情況僅在偵聽的源數據變更時才執行回調。也可以加上immediate: true
來使其立即生效watchEffect不用指明監視哪個屬性,監視的回調中用到哪個屬性,就監視哪個屬性。
//watchEffect所指定的回調中用到的數據只要發生變化,則直接重新執行回調。watchEffect(()=>{const?x1?=?sum.valueconst?x2?=?person.ageconsole.log('watchEffect執行了回調')
})
二、重寫 VDOM
優化前Virtual Dom
的diff
算法,需要遍歷所有節點,而且每一個節點都要比較舊的props和新的props有沒有變化。在Vue3.0中,只有帶PatchFlag
的節點會被真正的追蹤,在后續更新的過程中,Vue不會追蹤靜態節點,只追蹤帶有PatchFlag
的節點來達到加快渲染的效果。
<div><span>vue</span><span>{{msg}}</span><span?:id=?hello??class=?bar?>{{msg}}</span>
</div>
export?function?render(_ctx,_cache,$props,?$setup,$data,$options){return?(_openBlock(),_createBlock(??span ,null,[_createVNode(?span ,null,?vue?),_createVNode(?span ,null,_toDisplayString(_ctx.msg),?1?/*?TEXT?*/),_createVNode(?span ,{id:?_ctx,helloclass:??bar?},_toDisplayString(_ctx.msg),9?/*?TEXT,?PROPS?*/,?[?id?])}
上面的源碼中1 /* TEXT */
這個標記就是 PatchFlag
,Vue只會追蹤第二個和第三個帶有PatchFlag
的節點。
在第三個span標簽中PatchFlag
變成了 9 /* TEXT, PROPS */, [ id ]
,提示我們這個dom元素中不僅有TEXT
的變化,PROPS
也可能會變化,后邊數組中的內容則是有可能發生變化的屬性。而靜態添加的class沒有被標記是因為 dom 元素的靜態屬性在渲染的時候就已經創建了,并且是不會變動的。在后面進行更新的時候,diff 算法是不會去管它的。
三、響應式實現
3.1 Vue2.x 的響應式
vue官方文檔:https://cn.vuejs.org/v2/guide/reactivity.html
實現原理:
對象類型:通過
Object.defineProperty()
對屬性的讀取、修改進行攔截(數據劫持)。數組類型:通過重寫更新數組的一系列方法來實現攔截。(對數組的變更方法進行了包裹)。
Object.defineProperty(data,?'count',?{get?()?{},?set?()?{}
})
存在問題:
新增屬性、刪除屬性, 界面不會更新。
無法監聽數組下標和length長度的變化。
不支持 Map、Set、WeakMap 和 WeakSet。
3.2 Vue3.0 的響應式
實現原理:
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
通過Proxy(代理): 攔截對象中任意屬性的變化——屬性值的讀寫、屬性的添加、屬性的刪除等。
通過Reflect(反射): 對源對象的屬性進行操作。
MDN文檔中對Proxy與Reflect描述:
new?Proxy(data,?{//?攔截讀取屬性值get?(target,?prop)?{return?Reflect.get(target,?prop)},//?攔截設置屬性值或添加新屬性set?(target,?prop,?value)?{return?Reflect.set(target,?prop,?value)},//?攔截刪除屬性deleteProperty?(target,?prop)?{return?Reflect.deleteProperty(target,?prop)}
})proxy.name?=?'tom'
四、新的生命周期鉤子
去掉了vue2.0中的 beforeCreate 和 created 兩個階段,新增了一個
setup
。執行setup
時,組件實例尚未被創建。每個生命周期函數必須導入才可以使用,并且所有生命周期函數需要統一放在
setup
里使用。destroyed
銷毀后被重命名為unmounted
卸載后;beforeDestroy
銷毀前生命周期選項被重命名為beforeUnmount
卸載前。

五、新的組件
「5.1 片段(Fragment)」
Vue2: 組件必須有一個根標簽
<template><div><span></span><span></span></div>
</template>
Vue3: 組件可以沒有根標簽, 可以直接寫多個根節點,內部會將多個標簽包含在一個Fragment虛擬元素中
<template><span></span><span></span>
</template>
好處: 減少標簽層級, 減小內存占用,提升了渲染性能
5.2 Teleport
Teleport
?就像是一個「任意門」,將包裹組件html結構傳送到任何指定的地方。
例如我們日常開發中經常會使用到彈窗組件,Dialog組件會被渲染到一層層子組件內部,處理樣式、定位都變得十分困難。這時我們希望將組件掛載在body上面,來更方便的控制Dialog的樣式。簡單來說,我們既希望繼續在組件內部使用Dialog,又希望渲染的 DOM 結構不嵌套在組件內部的 DOM 中。就可以用到<Teleport>
, 它可以在「不改變組件內部元素父子關系」的情況下,建立一個傳送門將Dialog渲染的內容傳送到body上面。
<teleport?to=?body?>
<div?v-if=?isShow??class=?dialog?><div?class=?dialog?><h3>彈窗</h3><button?@click=?isShow?=?false?>關閉彈窗</button></div>
</div>
</teleport>

5.3 Suspense
等待異步組件時渲染一些額外內容,讓應用有更好的用戶體驗
它提供兩個
template slot
, 剛開始會渲染一個fallback
插槽下的內容, 直到到達某個條件后才會渲染default
插槽的正式內容, 通過使用Suspense
組件進行展示異步渲染更加簡單。
<template><div?class=?app?><h3>我是App組件</h3><Suspense><template?v-slot:default><NewSuspense/></template><template?v-slot:fallback><h3>加載中.....</h3></template></Suspense></div>
</template>
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助4000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
掃碼加我微信 ruochuan02、拉你進源碼共讀群
今日話題
目前建有江西|湖南|湖北?籍 前端群,想進群的可以加我微信 ruochuan12?進群。分享、收藏、點贊、在看我的文章就是對我最大的支持~