Note:Vue3

Vue3常見API:

  • reactive:
    reactive返回proxy對(duì)象,如果發(fā)現(xiàn)被訪問的屬性是引用類型,還會(huì)用reactive遞歸處理,屬性是可以被修改的。
  • shallowReactive:
    shallowReactive返回proxy對(duì)象,和reactive的區(qū)別是只建立第一層為響應(yīng)式,如果發(fā)現(xiàn)被訪問的屬性是引用類型也不會(huì)進(jìn)行遞歸代理,屬性是可以被修改的。
  • readonly:
    readonly返回proxy對(duì)象,如果發(fā)現(xiàn)被訪問的屬性是引用類型會(huì)進(jìn)行遞歸處理,但是屬性是只讀的,不能修改??梢宰鰌rops傳遞給子組件使用。
  • shallowReadonly:
    shallowReadonly返回proxy對(duì)象,shallowReadonly 僅對(duì)對(duì)象的第一次層屬性進(jìn)行只讀處理,對(duì)于嵌套的對(duì)象或數(shù)組,它不會(huì)進(jìn)行只讀保護(hù)。

Vue3 新特性有哪些?

1、優(yōu)化響應(yīng)式系統(tǒng):

  • 使用ES6的 Proxy配合Reflect 代替vue2的 Object.defineProperty ,不僅可以更高效地追蹤依賴關(guān)系,還解決了 Vue 2 中響應(yīng)式無法追蹤數(shù)組長(zhǎng)度變化和對(duì)象屬性添加的問題。

2、更好的支持 typeScript:
Vue3在源碼使用了 TypeScript,可以為開發(fā)者 提供更好的類型檢查和類型推斷。

3、新增 Composition API:

  • Composition API 提供了一種新的代碼組織和復(fù)用方式,它允許開發(fā)者將邏輯拆分成獨(dú)立的函數(shù)(稱為“組合函數(shù)”),并在setup中按需使用。這使得代碼更加模塊化,易于測(cè)試和維護(hù),特別是在大型項(xiàng)目中。

4、新增組件:

  • Fragment: template 模板可以有多個(gè)根元素。
  • Teleport 傳送門,允許Teleport中的內(nèi)容傳送到任意的 DOM 中。
  • Suspense 用于處理異步組件的加載狀態(tài),提供了更好的用戶體驗(yàn)。

5、支持多個(gè)根節(jié)點(diǎn)

6、Tree-shaking:支持搖樹優(yōu)化:
Vue3.x中的核心API都支持tree-shaking,這些API都是通過包引入的方式而不是直接掛載在vue原型上,只會(huì)對(duì)使用到的功能或特性進(jìn)行打包(按需打包),這意味著更多的功能和更小的體積。

7、diff算法的優(yōu)化:

  1. vue2中虛擬dom進(jìn)行全量對(duì)比
  2. Vue 3 的虛擬 DOM Diff 算法通過引入靜態(tài)標(biāo)記(PatchFlag)和靜態(tài)提升等優(yōu)化手段,顯著提高了渲染性能。PatchFlag 允許 Vue 在比較新舊節(jié)點(diǎn)時(shí)跳過未發(fā)生變化的靜態(tài)部分,只關(guān)注動(dòng)態(tài)變化的部分。靜態(tài)提升則通過復(fù)用未發(fā)生變化的節(jié)點(diǎn),減少了不必要的節(jié)點(diǎn)創(chuàng)建和銷毀操作。

8、移除了一些功能:

  • 移除v-on的鍵盤修飾符,鼓勵(lì)開發(fā)者使用鍵盤事件(如 keyCode 或 key)來替代;
  • 移除過濾器filter。

Vue3性能提升主要是通過哪幾方面體現(xiàn)的?

1、編譯階段優(yōu)化

  • diff算法優(yōu)化
    vue3在diff算法中相比vue2增加了靜態(tài)標(biāo)記Patchflag,在編譯template模板時(shí),給vnode添加的一個(gè)PatchFlag標(biāo)識(shí)信息,這個(gè)標(biāo)識(shí)信息可以反映哪些vnode具有動(dòng)態(tài)綁定的屬性或子節(jié)點(diǎn),在與上次的節(jié)點(diǎn)進(jìn)行對(duì)比時(shí)候,Vue會(huì)利用patchFlag來高效地識(shí)別出哪些是需要更新的節(jié)點(diǎn),并僅對(duì)這些節(jié)點(diǎn)進(jìn)行對(duì)比和更新操作。這樣可以避免不必要的DOM操作,從而提升渲染性能。
  • 靜態(tài)提升
    Vue3會(huì)對(duì)不參與更新的元素做靜態(tài)提升,只會(huì)在初始化的時(shí)候創(chuàng)建一次,重新渲染時(shí)直接復(fù)用。在初始化的時(shí)候會(huì)對(duì)該靜態(tài)元素打上特殊靜態(tài)標(biāo)記,值為-1,表示靜態(tài)提升,(特殊標(biāo)志是負(fù)整數(shù)表示永遠(yuǎn)不會(huì)用于 Diff),做了靜態(tài)提升后,未參與更新的元素,被放置在render 函數(shù)外,每次渲染的時(shí)候直接復(fù)用即可。
    沒做靜態(tài)提升之前,未參與更新的元素也在render函數(shù)內(nèi)部,會(huì)重復(fù)創(chuàng)建階段。

詳細(xì):

  • Vue 2在對(duì)比較新舊節(jié)點(diǎn)時(shí),會(huì)檢查每個(gè)節(jié)點(diǎn)是否是靜態(tài)的,如果是靜態(tài)的會(huì)跳過這個(gè)節(jié)點(diǎn)及其子節(jié)點(diǎn)的比較。雖然會(huì)跳過靜態(tài)節(jié)點(diǎn)的比較,但是Vue2并沒有做靜態(tài)提升,靜態(tài)根節(jié)點(diǎn)還是在render函數(shù)內(nèi),所以這些靜態(tài)根節(jié)點(diǎn)每次都會(huì)被重新創(chuàng)建渲染。
  • vue3在diff算法中相比vue2增加了靜態(tài)標(biāo)記Patchflag,在編譯template模板時(shí),給vnode添加的一個(gè)PatchFlag標(biāo)識(shí)信息,這個(gè)標(biāo)識(shí)信息可以反映哪些vnode具有動(dòng)態(tài)綁定的屬性或子節(jié)點(diǎn),在與上次的節(jié)點(diǎn)進(jìn)行對(duì)比時(shí)候,Vue會(huì)利用patchFlag來高效地識(shí)別出哪些是需要更新的節(jié)點(diǎn),并僅對(duì)這些節(jié)點(diǎn)進(jìn)行對(duì)比和更新操作。對(duì)不參與更新的元素做靜態(tài)提升,只會(huì)在初始化的時(shí)候創(chuàng)建一次,重新渲染時(shí)直接復(fù)用。在初始化的時(shí)候會(huì)對(duì)該靜態(tài)元素打上特殊靜態(tài)標(biāo)記,值為-1,表示靜態(tài)提升,這樣可以避免不必要的DOM操作,從而提升渲染性能。

2、源碼體積優(yōu)化

  • 相比Vue2,Vue3整體體積變小了,除了移出一些不常用的API,最重要的是優(yōu)化了對(duì) Tree shanking的支持。Vue3中的核心API都支持tree-shaking,這些API都需通過包引入的方式才能使用,只會(huì)對(duì)使用到的功能或特性進(jìn)行打包(按需打包),這意味著更多的功能和更小的體積。

3、響應(yīng)式系統(tǒng)優(yōu)化

  • vue2主要采用 object.defineProperty來劫持對(duì)象屬性,通過進(jìn)行深度遍歷所有屬性,給每個(gè)屬性添加getter和setter,實(shí)現(xiàn)響應(yīng)式攔截。
  • vue3采用proxy重寫了響應(yīng)式系統(tǒng),因?yàn)閜roxy是對(duì)整個(gè)對(duì)象進(jìn)行監(jiān)聽的,所以無需遞歸遍歷對(duì)象的屬性。
  • 可以監(jiān)聽到屬性的添加、刪除操作。
  • 可以監(jiān)聽到數(shù)組的索引和數(shù)組length屬性的操作。

4、事件優(yōu)化

  • 在Vue2中,每次渲染時(shí)都會(huì)重新創(chuàng)建事件處理函數(shù),即使是相同的事件處理邏輯。
  • 在Vue3中,引入了緩存事件處理函數(shù)的概念,它會(huì)將事件處理函數(shù)在編譯階段緩存起來,重新渲染的時(shí)候直接復(fù)用。
// 靜態(tài)提升例子:
//  Vue2的靜態(tài)節(jié)點(diǎn)
render(){
  return createVNode("div", null, "Hello World")
}

// Vue3的靜態(tài)節(jié)點(diǎn)
const staticLifting = createVNode("div", null, "Hello World")
function render(){
  // 直接使用 staticLifting 即可
}
<button @click="i++">plus</button>
// vue2
render(ctx){
  return createVNode("button", {
    onClick: function($event){
      ctx.i++;
    }
  })
}

// vue3
render(ctx, _cache){
  return createVNode("button", {
    onClick: cache[0] || (cache[0] = ($event) => (ctx.i++))
  })
}

Vue3和Vue2的區(qū)別?

1. 響應(yīng)式數(shù)據(jù)的監(jiān)聽方式不同:

  • Vue2 的響應(yīng)式數(shù)據(jù)監(jiān)聽是采用ES5的Object.definePropert() 對(duì)數(shù)據(jù)進(jìn)行劫持的;
  • Vue3 中使用ES6的Proxy()對(duì)數(shù)據(jù)進(jìn)行代理劫持。
  • 相比Object.definePropert(),ES6的Proxy()有以下優(yōu)點(diǎn):
  • Proxy代理監(jiān)聽的是整個(gè)對(duì)象,不需要通過遞歸+遍歷為對(duì)象屬性設(shè)置getter和setter進(jìn)行劫持,提高了性能;
  • Proxy可以監(jiān)聽到對(duì)象屬性的動(dòng)態(tài)添加和刪除;
  • 可以監(jiān)聽到數(shù)組的索引和數(shù)組length屬性的操作;
  • 如果對(duì)象的屬性也是對(duì)象的話,只有在被訪問的時(shí)候才會(huì)進(jìn)行遞歸響應(yīng)觀測(cè),提高了性能;

2. Vue3新增了組合式(Composition API):

  • Vue2是使用options API的,options API內(nèi)部的邏輯點(diǎn)是碎片化的,一個(gè)功能邏輯會(huì)出現(xiàn)在不同的位置,通過定義methods,computed,watch,data等options API,共同處理頁面邏輯。
  • Vue3新增了Composition API(組合API),同時(shí)仍然兼容Vue2中的Options API。組合式API,組件根據(jù)邏輯功能來組織代碼的,一個(gè)功能所定義的所有 API 會(huì)放在一起,通過函數(shù)分割復(fù)用代碼,將其封裝成一個(gè)hooks,hooks需要在setup函數(shù)中使用。

3. 定義數(shù)據(jù)變量和方法不同:

  • vue2是在對(duì)應(yīng)的選項(xiàng)中定義變量、方法、計(jì)算屬性等。在data選項(xiàng)中定義響應(yīng)式數(shù)據(jù),在method中定義方法。
  • Vue3需要從vue中導(dǎo)出reactive、ref、computed等API,這些API需要在一個(gè)setup鉤子函數(shù)中使用,通過使用reactive、ref來定義響應(yīng)式數(shù)據(jù)。

4. template模板支持:

  • Vue3 template 支持多個(gè)根節(jié)點(diǎn);
  • Vue2 template 只能支持單個(gè)根節(jié)點(diǎn)。

5. 生命周期函數(shù):

  1. vue2的生命周期是選項(xiàng)式的,,主要生命周期函數(shù)是beforeCreate、created、beforeMount、Mounted、beforeUpdate、updated、beforeDestory、destroyed;
  2. vue3的生命周期是組合式的,需要通過包引入的方式才可以時(shí)使用;
  • vue3用setup鉤子取代了beforeCreate和created鉤子函數(shù),setup函數(shù)在beforeCreate之前調(diào)用;
  • vue3將beforeDestory和destroyed這兩個(gè)鉤子函數(shù)的名稱改為onBeforeUnmount和onUnmounted。

6. Vue實(shí)例的創(chuàng)建方式不同:

  • Vue2是通過new一個(gè)Vue實(shí)例來創(chuàng)建Vue實(shí)例對(duì)象的;
  • Vue3需要引入createApp方法,然后調(diào)用該方法創(chuàng)建Vue對(duì)象。
// Vue2
import Vue from 'vue';
import App from './App.vue'
new Vue({
  render: h => h(App)
}).$mount('#app');

// Vue3
import {createApp} from 'vue';
import App from './App.vue'
createApp(App).mount('#app')

Options Api與Composition Api的區(qū)別?

代碼組織:
1、Options Api:選項(xiàng)式API內(nèi)部的邏輯點(diǎn)是碎片化的,一個(gè)功能邏輯會(huì)出現(xiàn)在不同的位置,通過定義methods,computed,watch,data等選項(xiàng)API,共同處理頁面邏輯。當(dāng)組件變得復(fù)雜時(shí),會(huì)降低代碼的可讀性和可維護(hù)性。
2、Composition API(組合式API),使用 ref、reactive、computed、watch 等函數(shù)來替代 Options API 中的對(duì)應(yīng)選項(xiàng)。組件根據(jù)邏輯功能來組織代碼,通過函數(shù)分割復(fù)用代碼,一個(gè)功能所定義的所有 API 會(huì)放在一起,這使得代碼更加集中和模塊化,易于閱讀和維護(hù)。( 更加的 高內(nèi)聚,低耦合 )。

邏輯復(fù)用:

  • 在vue2.0中,是通過mixin來實(shí)現(xiàn)邏輯復(fù)用的,當(dāng)使用多個(gè)mixin會(huì)存在兩個(gè)非常明顯的問題:命名沖突、數(shù)據(jù)來源不清晰
  • Composition Api是通過函數(shù)復(fù)用,通過將相同邏輯功能的代碼封裝成一個(gè)函數(shù),這些代碼片段可以包含狀態(tài)、計(jì)算屬性、方法等,可以在多個(gè)組件中重復(fù)使用,而不會(huì)引起命名沖突或數(shù)據(jù)來源不明確的問題。

總結(jié):

  • 在代碼組織和邏輯復(fù)用方面,Composition API是優(yōu)于Options API
  • 因?yàn)镃omposition API幾乎是函數(shù),會(huì)有更好的類型推斷;
  • Composition API 對(duì) tree-shaking 更友好,從而生成更小的包;
  • Composition API中見不到this的使用,減少了this指向不明的情況;
  • 如果是小型組件,可以繼續(xù)使用Options API,也是十分友好的。
  • 更好的測(cè)試,由于 Composition API 中的邏輯更加模塊化,它們也更易于進(jìn)行單元測(cè)試。

Vue3.0里為什么要用 Proxy API 替代 defineProperty API ?

1、vue2是采用 Object.defineProperty來監(jiān)聽對(duì)象的操作的,通過遍歷+遞歸的方式給每個(gè)屬性添加getter和setter進(jìn)行劫持。
存在以下的問題:

  • 檢測(cè)不到對(duì)象屬性的添加和刪除,Vue提供了set添加和delete刪除,但是這需要手動(dòng)調(diào)用,有額外的負(fù)擔(dān);
  • 監(jiān)聽不到通過數(shù)組索引添加新屬性和數(shù)組length屬性的操作;
  • 在初始化階段,需要對(duì)對(duì)象屬性進(jìn)行遍歷監(jiān)聽,如果是嵌套對(duì)象,即使沒有被訪問到,也會(huì)被遞歸監(jiān)聽,當(dāng)對(duì)象過深的時(shí)候會(huì)造成性能問題。

2、Proxy監(jiān)聽的是整個(gè)對(duì)象的操作:

  • Proxy 創(chuàng)建了一個(gè)對(duì)象的代理,這個(gè)代理可以攔截針對(duì)對(duì)象的任何操作(如讀取、賦值、函數(shù)調(diào)用等),而不僅僅是屬性訪問。因此,它可以更全面地追蹤對(duì)象的變化。
  • Proxy不需要預(yù)先知道要監(jiān)聽哪些屬性,它可以動(dòng)態(tài)地處理對(duì)象的屬性添加和刪除。
  • 可以監(jiān)聽到數(shù)組的索引和數(shù)組length屬性的操作;
  • 對(duì)于嵌套對(duì)象,只有在被訪問到的時(shí)候才會(huì)對(duì)其進(jìn)行遞歸響應(yīng)觀測(cè),這有助于提高性能;
  • Proxy提供了多達(dá)13種攔截方法,這些方法可以覆蓋對(duì)象的各種操作,提供了更大的靈活性和控制力。

Proxy 只會(huì)代理對(duì)象的第一層,那么 Vue3 又是怎樣處理這個(gè)問題的呢?

當(dāng)訪問到深層嵌套對(duì)象的話,會(huì)觸發(fā)getter,會(huì)判斷當(dāng)前 Reflect.get 的返回值是否是已經(jīng)代理過的對(duì)象,如果是一個(gè)普通對(duì)象則再使用 reactive 方法做代理, 這樣就實(shí)現(xiàn)了深度觀測(cè)。

說說Vue 3.0中Treeshaking特性?舉例說明一下?

1、什么是Tree shaking?
Tree shaking 是一種通過清除多余代碼方式來優(yōu)化項(xiàng)目打包體積的技術(shù),專業(yè)術(shù)語叫 (Dead code elimination)簡(jiǎn)單來講,就是在保持代碼運(yùn)行結(jié)果不變的前提下,去除無用的代碼
2、Tree shaking原理?
Tree shaking是基于ES6模塊化方案 (import與exports),模塊之間的依賴關(guān)系是高度確定和靜態(tài)的,與運(yùn)行狀態(tài)無關(guān),可以進(jìn)行可靠的靜態(tài)分析。在打包過程中 靜態(tài)分析 模塊之間的導(dǎo)入導(dǎo)出,確定哪些導(dǎo)出的模塊沒有被引用并打上標(biāo)記,最終將其刪除。

  • 在Vue2中,很多API 都是掛載在Vue原型上的,程序無法檢測(cè)到該對(duì)象的哪些屬性在代碼中被使用到。
  • 而Vue3優(yōu)化了對(duì)tree shaking的支持,所有的核心API都支持Tree Shaking, 需要通過包引入的方式才可以使用。如果您不使用其某些功能,它們將不會(huì)包含在您的基礎(chǔ)包中。

Tree shaking無非就是做了兩件事:

  • 編譯階段利用ES6 Module判斷哪些模塊已經(jīng)加載
  • 判斷哪些模塊和變量未被使用或者引用,進(jìn)而刪除對(duì)應(yīng)代碼
    3、Tree shaking作用(好處)?
  • 減少程序體積(更?。?;
  • 減少程序執(zhí)行時(shí)間(更快);
  • 便于將來對(duì)程序架構(gòu)進(jìn)行優(yōu)化(更友好)。

watch 和 watchEffect 的區(qū)別?

watch 和 watchEffect 都是監(jiān)聽器,watchEffect 是一個(gè)副作用函數(shù)。
它們之間的區(qū)別有:

  • watch :既要指明監(jiān)視的數(shù)據(jù)源,也要指明監(jiān)視的回調(diào)。
  • watchEffect 可以自動(dòng)監(jiān)聽數(shù)據(jù)源作為依賴。不用指明監(jiān)視哪個(gè)數(shù)據(jù),監(jiān)視的回調(diào)中用到哪個(gè)數(shù)據(jù),那就監(jiān)視哪個(gè)數(shù)據(jù)。
  • watch 可以訪問改變之前和之后的值,watchEffect 只能獲取改變后的值。
  • watch 依賴的屬性改變后才會(huì)執(zhí)行,初始化的時(shí)候不會(huì)立即執(zhí)行,但是可以通過 watch 的配置項(xiàng) immediate 來改變;而 watchEffect 初始化的時(shí)候會(huì)立即執(zhí)行。
    watchEffect有點(diǎn)像 computed :
  • computed 注重的計(jì)算出來的值(回調(diào)函數(shù)的返回值), 所以必須要寫返回值。
  • watcheffect注重的是過程(回調(diào)函數(shù)的函數(shù)體),所以不用寫返回值。

ref與reactive的區(qū)別?

  • ref與reactive 是 Vue3 新推出的主要 API 之一,主要用于創(chuàng)建響應(yīng)式數(shù)據(jù)。
  • ref 函數(shù)創(chuàng)建的響應(yīng)式數(shù)據(jù),在模板中可以直接被使用,在 JS 中需要通過 .value 的形式才能使用。
  • ref 函數(shù)可以接收原始數(shù)據(jù)類型與引用數(shù)據(jù)類型。
  • reactive 函數(shù)只能接收引用數(shù)據(jù)類型。
  • ref 底層還是使用 reactive 來做,ref 是在 reactive 上在進(jìn)行封裝的,增強(qiáng)了其能力,使它支持了對(duì)原始數(shù)據(jù)類型的處理。
  • 在 Vue3 中 reactive 能做的,ref 也能做,reactive 不能做的,ref 也能做。
  • ref還能獲取組件的實(shí)例。

setup() 函數(shù)特性:

  • setup 函數(shù)有兩個(gè)參數(shù):(props、context(包含attrs、slots、emit));
  • setup函數(shù)在 生命周期 beforeCreate 和 created 兩個(gè)鉤子函數(shù)之前執(zhí)行;
  • setup函數(shù)中不能使用this,因?yàn)?setup 函數(shù)執(zhí)行時(shí),組件實(shí)例尚未被創(chuàng)建,Vue 為了避免我們錯(cuò)誤的使用,直接將 setup函數(shù)中的this修改成了undefined;
  • 與模板一起使用:需要返回一個(gè)對(duì)象,將需要在模板中使用的變量和方法return 出去,不然無法在模板中使用
  • setup函數(shù)只能是同步的不能是異步的。
  • setup函數(shù)默認(rèn)暴露組件內(nèi)部的屬性和方法。
  • setup 函數(shù)中的 props 是響應(yīng)式的,它是一個(gè)reactive。不能使用ES6的解構(gòu)來結(jié)構(gòu)props,因?yàn)樗鼤?huì)消除 props 的響應(yīng)性。如果需要解構(gòu) props,可以通過使用 setup 函數(shù)中的 toRefs 來完成解構(gòu)操作:
import {toRefs} from 'vue'
setup(props) {
    const { name } = toRefs(props);
    console.log(name.value);
    onMounted(() => {
        console.log('name: ' + props.name);
    })

}

script setup 是干啥的?

scrtpt setup 是 vue3.2 的語法糖,簡(jiǎn)化了組合式 API 的寫法,并且運(yùn)行性能更好。
script setup 語法糖的特點(diǎn):

  • 屬性和方法無需返回,可以直接在template模板中使用。
  • 引入組件的時(shí)候,會(huì)自動(dòng)注冊(cè),無需通過 components 手動(dòng)注冊(cè)。
  • 使用 defineProps 接收父組件傳遞的值、defineEmits 定義自定義事件。
  • 使用 useAttrs 獲取額外沒有在props配置的屬性,useSlots 獲取插槽。
  • 默認(rèn)不會(huì)對(duì)外暴露任何屬性方法,內(nèi)部自動(dòng)調(diào)用exporse方法,如果有需要可使用 defineExpose 指定暴露的屬性、方法。
  • defineOptions可以關(guān)閉屬性透?jìng)骱投x組件name值。
export const enum PatchFlags {
  // 表示vnode具有動(dòng)態(tài)textContent的元素
  TEXT = 1,
  // 表示vnode具有動(dòng)態(tài)的class
  CLASS = 1 << 1,
  // 表示具有動(dòng)態(tài)的style
  STYLE = 1 << 2,
  // 表示具有動(dòng)態(tài)的非class和style的props
  PROPS = 1 << 3,
  // 表示props具有動(dòng)態(tài)的key,與CLASS、STYLE、PROPS沖突
  FULL_PROPS = 1 << 4,
  // 表示有監(jiān)聽事件(在同構(gòu)期間需要添加)
  HYDRATE_EVENTS = 1 << 5,
  // 表示vnode是個(gè)children順序不會(huì)改變的fragment
  STABLE_FRAGMENT = 1 << 6,
  // 表示children帶有key的fragment
  KEYED_FRAGMENT = 1 << 7,
  // 表示children沒有key的fragment
  UNKEYED_FRAGMENT = 1 << 8,
  // 表示vnode只需要非props的patch。例如只有標(biāo)簽中只有ref或指令
  NEED_PATCH = 1 << 9,
  // 表示vnode存在動(dòng)態(tài)的插槽。例如動(dòng)態(tài)的插槽名
  DYNAMIC_SLOTS = 1 << 10,
  // 表示用戶在模板的根級(jí)別存在注釋而創(chuàng)建的片段,這是一個(gè)僅用于開發(fā)的標(biāo)志,因?yàn)樽⑨屧谏a(chǎn)中被剝離
  DEV_ROOT_FRAGMENT = 1 << 11,
  
  // 以下都是一些特殊的flag,它們不能使用位運(yùn)算進(jìn)行匹配
  // 表示vnode經(jīng)過靜態(tài)提升
  HOISTED = -1,
  // diff算法應(yīng)該退出優(yōu)化模式
  BAIL = -2
}

vue3 reactive響應(yīng)式原理:

  • vue3 響應(yīng)式主要是采用發(fā)布者訂閱者模式 + es6的 Proxy 代理實(shí)現(xiàn)的。
  • 首先判斷目標(biāo)對(duì)象是否是一個(gè)對(duì)象,如果不是,直接警告提示。
  • 判斷目標(biāo)對(duì)象有沒有被 Proxy 代理過,如果已經(jīng)被代理過了直接返回目標(biāo)對(duì)象。
  • 否則調(diào)用createReactiveObject方法對(duì)目標(biāo)對(duì)象進(jìn)行 Proxy 代理,設(shè)置getter和setter進(jìn)行攔截。當(dāng) Proxy 對(duì)象中的屬性被訪問的時(shí)候,會(huì)觸發(fā)getter,此時(shí)會(huì)去獲取值,如果該值是對(duì)象且沒有被Proxy代理過的話,會(huì)遞歸調(diào)用reactive去實(shí)現(xiàn)對(duì)其進(jìn)行 Proxy 代理。在getter中會(huì)調(diào)用track收集effect;當(dāng) 對(duì)象的屬性被修改或者新增了屬性的是,會(huì)調(diào)用trigger去通過訂閱該屬性的effect做出相應(yīng)的更新;
  • track方法的作用就是收集effect,收集的effect會(huì)保存在全局WeakMap結(jié)構(gòu)的targetMap對(duì)象中,其key值是需要代理的目標(biāo)對(duì)象,value值是也是一個(gè)depsMap對(duì)象,它是一個(gè) Map 結(jié)構(gòu)的對(duì)象,是用來保存代理對(duì)象的key值所對(duì)應(yīng)的所有effect,所有effect都是存儲(chǔ)在Set結(jié)構(gòu)的集合中的。
  • trigger方法主要是通知屬性對(duì)應(yīng)的所有effect去更新,會(huì)根據(jù)代理對(duì)象target去targetMap中查找代理對(duì)象所對(duì)應(yīng)的depsMap,然后根據(jù)訪問的代理對(duì)象的key值去depsMap查找該key的所對(duì)應(yīng)的effect集合,然后遍歷去執(zhí)行每個(gè)effect里的更新方法,進(jìn)而做出相應(yīng)的更新操作。
  • effect是一個(gè)包裝函數(shù),接收一個(gè)副作用函數(shù),它通常代表了一個(gè)需要響應(yīng)數(shù)據(jù)變化的操作。當(dāng)屬性被訪問的時(shí)候,會(huì)觸發(fā)getter,此時(shí)會(huì)將當(dāng)前激活的activeEffect收集到當(dāng)前屬性的effect收集器中,待收到數(shù)據(jù)發(fā)生變化的消息時(shí),會(huì)調(diào)用自身對(duì)應(yīng)配置下的更新方法重新進(jìn)行更新。

Vue3 ref原理:

ref利用了ES6的類的屬性訪問器原理,它有一個(gè)value屬性,用于保存ref的值,在構(gòu)造函數(shù)被創(chuàng)建的時(shí)候會(huì)在constructor獲取初始值,如果值是對(duì)象的話,會(huì)使用reactive進(jìn)行響應(yīng)代理。value被設(shè)置了get和set進(jìn)行監(jiān)聽,當(dāng)value被訪問的時(shí)候會(huì)觸發(fā)get,在get里調(diào)用track方法進(jìn)行依賴的收集。當(dāng)對(duì)value進(jìn)行賦值的時(shí)候會(huì)觸發(fā)set,在set里會(huì)調(diào)用trigger方法通知所有的依賴該屬性的方法也就是所有的effect進(jìn)行更新。如果修改的值是一個(gè)對(duì)象的話,會(huì)調(diào)用reactive來對(duì)其進(jìn)行響應(yīng)式處理。

為什么 ref 類型數(shù)據(jù),必須要通過 .value 訪問值呢?

a. 因?yàn)?ref 既可以處理基本數(shù)據(jù)類型的數(shù)據(jù),也可以處理對(duì)象類型的數(shù)據(jù),但是基本數(shù)據(jù)類型的數(shù)據(jù)無法通過 proxy 進(jìn)行代理。
b. 而 vue 結(jié)合ES6的類的屬性訪問器原理,通過 get value() 和 set value() 定義了兩個(gè)屬性函數(shù),通過主動(dòng)觸發(fā)這兩個(gè)函數(shù)的形式來進(jìn)行依賴收集和依賴觸發(fā)。
c. 所以我們必須通過 .value 來保證數(shù)據(jù)響應(yīng)式。

computed的原理:

  1. 計(jì)算屬性有函數(shù)式寫法和對(duì)象寫法,當(dāng)用戶傳入的是一個(gè)函數(shù)的時(shí)候,默認(rèn)使用的是getter只讀操作;當(dāng)用戶傳入的是一個(gè)對(duì)象時(shí),用戶可以設(shè)置getter,setter,此時(shí)計(jì)算屬性具備可讀可寫的能力。
  2. 在vue3中實(shí)現(xiàn)計(jì)算屬性,第一步就是處理、收集用戶設(shè)置的getter和setter;
  3. 然后實(shí)例化一個(gè)計(jì)算屬性的類,在類的構(gòu)造器中,會(huì)實(shí)例化一個(gè)effect,這個(gè)effect接收用戶的設(shè)置的getter和一個(gè)調(diào)度函數(shù),用于計(jì)算計(jì)算屬性的值和更新計(jì)算屬性的_dirty屬性。計(jì)算屬性的effect使用的是lazy配置,在初始化的時(shí)候是不會(huì)立即執(zhí)行去獲取值的,因?yàn)橐紤]到計(jì)算屬性是否有被使用。
  4. 計(jì)算屬性類中有一個(gè)_dirty屬性,默認(rèn)為true,用于判斷計(jì)算屬性是否需要重新計(jì)算;還有一個(gè)_value屬性,利用ES6類的屬性訪問器原理,被設(shè)置了get和set進(jìn)行監(jiān)聽,當(dāng)計(jì)算屬性被修改時(shí),會(huì)觸發(fā)set,在set中只是簡(jiǎn)單的執(zhí)行用戶設(shè)置的setter;當(dāng)計(jì)算屬性value被訪問的時(shí)候會(huì)觸發(fā)get,在get里會(huì)調(diào)用effect的run方法也就是用戶設(shè)置的getter去獲取值,此時(shí)會(huì)訪問依賴屬性的值,依賴的屬性會(huì)將當(dāng)前活躍的計(jì)算屬性的effect收集起來。在get中還會(huì)將_dirty設(shè)置為false,如果依賴屬性沒有發(fā)生變化是不需要重新計(jì)算值的。
  5. 當(dāng)依賴的屬性發(fā)生變化的時(shí)候,會(huì)去遍歷該屬性所有的effect,此時(shí)會(huì)執(zhí)行計(jì)算屬性effect的調(diào)度函數(shù),將_dirty設(shè)置為true,當(dāng)計(jì)算屬性再次被訪問的時(shí)候,此時(shí)的_dirty為true,會(huì)重新計(jì)算值。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容