大家好,我是若川。持續組織了6個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列
一、Vue3
Vue3中文文檔[1]
Vue3是什么,與Vue2區別(What)
Performance
:性能更強。Tree shaking support
:可以將無用模塊“剪輯”,僅打包需要的。Composition API
:組合式API
Fragment, Teleport, Suspense
:“碎片”,Teleport
即Protal傳送門
,“懸念”Better TypeScript support
:更優秀的Ts支持Custom Renderer API
:暴露了自定義渲染API
為什么要大版本迭代 (Why)
主流瀏覽器對新的JavaScript語言特性的普遍支持。
當前Vue代碼庫隨著時間的推移而暴露出來的設計和體系架構問題。
他是如何提升的(How)
響應式系統提升: 使用Proxy提升了響應式的性能和功能
編譯優化: 標記和提升所有的靜態節點,diff時只需要對比動態節點內容
事件緩存: 提供了事件緩存對象cacheHandlers,無需重新創建函數直接調用緩存的事件回調
打包和體積優化: 按需引入,Tree shaking支持(ES Module)
二、編碼
全局API
【新增】createApp: 入口文件(main.ts)掛載方式
import?{?createApp?}?from?"vue";import?App?from?"./App.vue";//?Vue2new?Vue({render:?(h)?=>?h(App)}).$mount("#app");//?Vue3createApp(App).use(**).mount("#app");
【修改】
2.x 全局 API | 3.x 實例 API (app) |
---|---|
Vue.config | app.config |
Vue.config.productionTip | 無 |
Vue.config.ignoredElements | app.config.isCustomElement |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
config.ignoredElements替換為
config.isCustomElement
引入此配置選項的目的是支持原生自定義元素,因此重命名可以更好地傳達它的功能,新選項還需要一個比舊的 string/RegExp 方法提供更多靈活性的函數:
//?Vue2Vue.config.ignoredElements?=?[//?用一個?`RegExp`?忽略所有“ion-”開頭的元素//?僅在?2.5+?支持/^ion-/]//?Vue3const?app?=?Vue.createApp({})app.config.isCustomElement?=?tag?=>?tag.startsWith('ion-')
Vue.prototype
替換為 config.globalProperties
在Vue 2中,Vue.prototype通常用于添加可在所有組件中訪問的屬性。
Vue 3中的等效項是config.globalProperties。在實例化應用程序內的組件時,將復制這些屬性
//?Vue2Vue.prototype.$http?=?()?=>?{}//?Vue3const?app?=?Vue.createApp({})app.config.globalProperties.$http?=?()?=>?{}
生命周期
2.0生命周期 | 3.0生命周期 |
---|---|
beforeCreate(組件創建之前) | setup() |
created(組件創建完成) | setup() |
beforeMount(組件掛載之前) | onBeforeMount(組件掛載之前) |
mounted(組件掛載完成) | onMounted(組件掛載完成) |
beforeUpdate(數據更新,虛擬DOM打補丁之前) | onBeforeUpdate(數據更新,虛擬DOM打補丁之前) |
updated(數據更新,虛擬DOM渲染完成) | onUpdated(數據更新,虛擬DOM渲染完成) |
beforeDestroy(組件銷毀之前) | onBeforeUnmount(組件銷毀之前) |
destroyed(組件銷毀之后) | onUnmounted(組件銷毀之后) |
activated(被 keep-alive 緩存的組件激活時調用) | onActivated(被激活時執行) |
deactivated(被 keep-alive 緩存的組件停用時調用) | onDeactivated(比如從 A 組件,切換到 B 組件,A 組件消失時執行) |
errorCaptured(當捕獲一個來自子孫組件的錯誤時被調用) | onErrorCaptured(當捕獲一個來自子孫組件的異常時激活鉤子函數) |
新特性
Options API => Composition API


setup()
import?{toRefs}?from?'vue'export?default?{name:?'demo',props:{name:?String,},// setup()作為在組件內使用Composition API的入口點。//?執行時機是在beforeCreate和created之間,不能使用this獲取組件的其他變量,//?而且不能是異步。setup返回的對象和方法,都可以在模版中使用。setup(props,?context){//?這里需要使用toRefs來進行解構//?這里的props與vue2基本一致,當然這里的name也可以直接在template中使用const?{?name?}=toRefs(props);console.log(name.value);//?context是一個上下文對象//【從原來?2.x?中?this?選擇性地暴露了一些?property(attrs/emit/slots)】//?屬性,同vue2的?$attrsconsole.log(context.attrs);//?插槽console.log(context.slots);//?事件,同vue2的?$emitconsole.log(context.emit);//?生命周期鉤子onMounted(()?=>?{})}}
注意點:
注意
props
對象是響應式的,watchEffect
或watch
會觀察和響應props
的更新,不要解構props
對象,那樣會使其失去響應性attrs
和slots
都是內部組件實例上對應項的代理,可以確保在更新后仍然是最新值。所以可以解構,無需擔心后面訪問到過期的值this
在setup()
中不可用。由于setup()
在解析 2.x 選項前被調用,setup()
中的this
將與 2.x 選項中的this
完全不同。同時在setup()
和 2.x 選項中使用this
時將造成混亂
響應式reactive,ref
import?{?ref,?reactive,?toRefs?}?from?'vue';setup()?{//?ref//?ref?對我們的值創建了一個響應式引用const?counter?=?ref(0);?//?reactive//?接收一個普通對象然后返回該普通對象的響應式代理const?obj?=?{a:1};const?objReactive?=?reactive(obj);const?add?=?()?=>?{counter.value++;objReactive.a++;}return?{counter,??//?return返回會自動解套【在模板中不需要.value】objReactive,add,};?//?這里返回的任何內容都可以用于組件的其余部分}
ref | reactive | |
---|---|---|
入參 | 基本類型 | 引用類型 |
返回值 | 響應式且可變的 ref 對象 | 響應式代理(Proxy) |
訪問方式 | 1.ref 對象擁有一個指向內部值的單一屬性 .value 2.在dom和setup()的return中會自動解套 3.ref 作為 reactive 對象的 property 被訪問或修改時,也將自動解套 | 直接.訪問即可 |
問題 & 注意點: 因為reactive是組合函數【對象】,所以必須始終保持對這個所返回對象的引用以保持響應性,不能解構該對象或者展開
例如:
const { a } = objReactive
或者return { ...objReactive }
解決方法:
toRefs
API
用來提供解決此約束的辦法——它將響應式對象的每個 property 都轉成了相應的 ref【把對象轉成了ref】。
import?{?reactive,?toRefs?}?from?'vue';setup()?{//?reactive//?接收一個普通對象然后返回該普通對象的響應式代理const?obj?=?{a:1};const?objReactive?=?reactive(obj);//?toRefs//?將響應式對象轉換為普通對象,其中結果對象的每個?property?都是指向原始對象相應?property?的refconst?objRef?=?toRefs(objReactive);const?{?a?}?=?objRef;const?addObj?=?()?=>?{a.value++;console.log(a.value,?objRef,?objReactive,?obj);}return?{...objRef,addObj};?}
Hooks方式
counter.js
import?{?ref?}?from?'vue';export?function?useCounter()?{const?count?=?ref(0);const?decrement?=?()?=>?{count.value--;}const?increment?=?()?=>?{count.value++;}return?{count,decrement,increment}}
父組件
<template><h2>{{?count?}}</h2><button?@click="increment">increment</button><button?@click="decrement">decrement</button></template><script>import?{?useCounter?}?from?'./counter.js';export?default?{setup()?{return?{...useCounter(),};}}</script>
響應式計算和偵聽
computed
const?count?=?ref(1)/*不支持修改【只讀的】?*/const?plusOne?=?computed(()?=>?count.value?+?1)plusOne.value++?//?錯誤!/*【可更改的】?*/const?plusOne?=?computed({get:?()?=>?count.value?+?1,set:?(val)?=>?{count.value?=?val?-?1},})
watch
//?直接偵聽一個?refconst?count?=?ref(0)watch(count,?(count,?prevCount)?=>?{/*?...?*/})//?也可以使用數組來同時偵聽多個源watch([fooRef,?barRef],?([foo,?bar],?[prevFoo,?prevBar])?=>?{/*?...?*/})
watchEffect
定義:在響應式地跟蹤其依賴項時立即運行一個函數,并在更改依賴項時重新運行它
第一個參數:
effect
,顧名思義,就是包含副作用的函數。如下代碼中,副作用函數的作用是:當count
被訪問時,旋即(隨即)在控制臺打出日志。返回值:也是一個函數,顯式調用可以清除watchEffect,組件卸載時會被隱式調用
const?count?=?ref(0);const?stop?=?watchEffect(()?=>?console.log(count.value));?//?->?logs?0setTimeout(()?=>?{count.value++;?//?->?logs?1},?100);//?清除watchEffectstop();
清除副作用(onInvalidate)
watchEffect
的第一個參數——effect
函數——自己也有參數:叫onInvalidate
,也是一個函數,用于清除 effect
產生的副作用。
onInvalidate
被調用的時機很微妙:它只作用于異步函數,并且只有在如下兩種情況下才會被調用:
當
effect
函數被重新調用時當監聽器被注銷時(如組件被卸載了)
import?{?asyncOperation?}?from?"./asyncOperation";const?id?=?ref(0);watchEffect((onInvalidate)?=>?{const?token?=?asyncOperation(id.value);//?onInvalidate?會在?id?改變時或停止偵聽時,取消之前的異步操作(asyncOperation)onInvalidate(()?=>?{token.cancel();});});
第二個參數:options
主要作用是指定調度器,即何時運行副作用函數。
//?fire?before?component?updateswatchEffect(()?=>?{/*?...?*/},{flush:?"pre",onTrigger(e)?{//?依賴項變更導致副作用被觸發時,被調用debugger;},onTrack(e)?{//?依賴項變更會導致重新追蹤依賴時,被調用【調用次數為被追蹤的數量】debugger},});
三、源碼
未完待續...
四、其他相關
Vite2.0,2月17號正式發布
中文文檔:https://cn.vitejs.dev/
五、感悟
優點:很優秀
缺點:他的對手(React),更優秀
雖然好多地方神似React,但是我們也可以從中看出,他們的都源于比較成熟的編程范式——FP(Functional Programming)。
框架只是工具,解決問題才是終極目標;我們還是要把重點放在領悟框架的設計思想上;悟到了,才是真正掌握了解決問題的手段。(抄的)
參考文檔:
https://juejin.cn/post/6858558735695937544#heading-0
https://blog.csdn.net/qq_34998786/article/details/113287653
https://www.jianshu.com/p/ad38a1f27d0f
https://juejin.cn/post/6844904134303301645
https://juejin.cn/post/6858558735695937544#heading-25
https://juejin.cn/post/6888925879243079687
https://www.jianshu.com/p/a8fdf52d0bcf
參考資料
[1]
Vue3中文文檔: https://v3.cn.vuejs.org/
- END -·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。
識別上方二維碼加我微信、拉你進源碼共讀群
今日話題
略。分享、收藏、點贊、在看我的文章就是對我最大的支持~