国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

圖解 Vue 響應(yīng)式原理

這篇具有很好參考價(jià)值的文章主要介紹了圖解 Vue 響應(yīng)式原理。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

  • Vue 初始化
  • 模板渲染
  • 組件渲染

為了便于理解,本文將從以下兩個(gè)方面進(jìn)行探索:

  • 從 Vue 初始化,到首次渲染生成 DOM 的流程。

  • 從 Vue 數(shù)據(jù)修改,到頁面更新 DOM 的流程。

Vue 初始化

先從最簡(jiǎn)單的一段 Vue 代碼開始:
"""

<template>
  <div>
	{{ message }}
  </div>
</template>
<script>
new Vue({
  data() {
	return {
	  message: "hello world",
	};
  },
});
</script>

"""


這段代碼很簡(jiǎn)單,最終會(huì)在頁面上打印一個(gè) hello world,它是如何實(shí)現(xiàn)的呢?

我們從源頭:new Vue 的地方開始分析。
"""

// 執(zhí)行 new Vue 時(shí)會(huì)依次執(zhí)行以下方法
// 1. Vue.prototype._init(option)
// 2. initState(vm)
// 3. observe(vm._data)
// 4. new Observer(data)

// 5. 調(diào)用 walk 方法,遍歷 data 中的每一個(gè)屬性,監(jiān)聽數(shù)據(jù)的變化。
function walk(obj) {
  const keys = Object.keys(obj);
  for (let i = 0; i < keys.length; i++) {
	defineReactive(obj, keys[i]);
  }
}

// 6. 執(zhí)行 defineProperty 監(jiān)聽數(shù)據(jù)讀取和設(shè)置。
function defineReactive(obj, key, val) {
  // 為每個(gè)屬性創(chuàng)建 Dep(依賴搜集的容器,后文會(huì)講)
  const dep = new Dep();
  // 綁定 get、set
  Object.defineProperty(obj, key, {
	get() {
	  const value = val;
	  // 如果有 target 標(biāo)識(shí),則進(jìn)行依賴搜集
	  if (Dep.target) {
		dep.depend();
	  }
	  return value;
	},
	set(newVal) {
	  val = newVal;
	  // 修改數(shù)據(jù)時(shí),通知頁面重新渲染
	  dep.notify();
	},
  });
}

"""
數(shù)據(jù)描述符綁定完成后,我們就能得到以下的流程圖:


圖解 Vue 響應(yīng)式原理


圖中我們可以看到,Vue 初始化時(shí),進(jìn)行了數(shù)據(jù)的 get、set 綁定,并創(chuàng)建了一個(gè) Dep 對(duì)象。

對(duì)于數(shù)據(jù)的 get、set 綁定我們并不陌生,但是 Dep 對(duì)象什么呢?

Dep 對(duì)象用于依賴收集,它實(shí)現(xiàn)了一個(gè)發(fā)布訂閱模式,完成了數(shù)據(jù) Data 和渲染視圖 Watcher 的訂閱,我們一起來剖析一下。
"""

class Dep {
  // 根據(jù) ts 類型提示,我們可以得出 Dep.target 是一個(gè) Watcher 類型。
  static target: ?Watcher;
  // subs 存放搜集到的 Watcher 對(duì)象集合
  subs: Array<Watcher>;
  constructor() {
	this.subs = [];
  }
  addSub(sub: Watcher) {
	// 搜集所有使用到這個(gè) data 的 Watcher 對(duì)象。
	this.subs.push(sub);
  }
  depend() {
	if (Dep.target) {
	  // 搜集依賴,最終會(huì)調(diào)用上面的 addSub 方法
	  Dep.target.addDep(this);
	}
  }
  notify() {
	const subs = this.subs.slice();
	for (let i = 0, l = subs.length; i < l; i++) {
	  // 調(diào)用對(duì)應(yīng)的 Watcher,更新視圖
	  subs[i].update();
	}
  }
}

"""
根據(jù)對(duì) Dep 的源碼分析,我們得到了下面這張邏輯圖:


圖解 Vue 響應(yīng)式原理


了解 Data 和 Dep 之后,我們來繼續(xù)揭開 Watcher 的面紗。
"""

class Watcher {
  constructor(vm: Component, expOrFn: string | Function) {
	// 將 vm._render 方法賦值給 getter。
	// 這里的 expOrFn 其實(shí)就是 vm._render,后文會(huì)講到。
	this.getter = expOrFn;
	this.value = this.get();
  }
  get() {
	// 給 Dep.target 賦值為當(dāng)前 Watcher 對(duì)象
	Dep.target = this;
	// this.getter 其實(shí)就是 vm._render
	// vm._render 用來生成虛擬 dom、執(zhí)行 dom-diff、更新真實(shí) dom。
	const value = this.getter.call(this.vm, this.vm);
	return value;
  }
  addDep(dep: Dep) {
	// 將當(dāng)前的 Watcher 添加到 Dep 收集池中
	dep.addSub(this);
  }
  update() {
	// 開啟異步隊(duì)列,批量更新 Watcher
	queueWatcher(this);
  }
  run() {
	// 和初始化一樣,會(huì)調(diào)用 get 方法,更新視圖
	const value = this.get();
  }
}

"""


源碼中我們看到,Watcher 實(shí)現(xiàn)了渲染方法 _render

和 Dep 的關(guān)聯(lián), 初始化 Watcher 的時(shí)候,打上

Dep.target 標(biāo)識(shí),然后調(diào)用 get 方法進(jìn)行頁面渲

染。加上上文的 Data,目前 Data、Dep、Watcher

三者的關(guān)系如下:


圖解 Vue 響應(yīng)式原理


我們?cè)倮ù幌抡麄€(gè)流程:

Vue 通過defineProperty 完成了 Data 中所有數(shù)據(jù)

的代理,當(dāng)數(shù)據(jù)觸發(fā) get 查詢時(shí),會(huì)將當(dāng)前的

Watcher 對(duì)象加入到依賴收集池 Dep 中,當(dāng)數(shù)據(jù)

Data 變化時(shí),會(huì)觸發(fā) set 通知所有使用到這個(gè) Data

的 Watcher 對(duì)象去 update 視圖。

目前的整體流程如下:


圖解 Vue 響應(yīng)式原理


上圖的流程中 Data 和 Dep 都是 Vue 初始化時(shí)創(chuàng)建的,但現(xiàn)在我們并不知道 Wacher 是從哪里創(chuàng)建的,帶著這個(gè)問題,我們接著往下探索。

模板渲染

上文中,我們分析了初始化 Vue 過程中處理數(shù)據(jù)的

部分,接下來,我們分析一下數(shù)據(jù)渲染的部分。

其實(shí) new Vue 執(zhí)行到最后,會(huì)調(diào)用 mount 方法,

將 Vue 實(shí)例渲染成 dom 。
"""

// new Vue 執(zhí)行流程。
// 1. Vue.prototype._init(option)
// 2. vm.$mount(vm.$options.el)
// 3. render = compileToFunctions(template) ,編譯 Vue 中的 template 模板,生成 render 方法。
// 4. Vue.prototype.$mount 調(diào)用上面的 render 方法掛載 dom。
// 5. mountComponent

// 6. 創(chuàng)建 Watcher 實(shí)例
const updateComponent = () => {
  vm._update(vm._render());
};
// 結(jié)合上文,我們就能得出,updateComponent 就是傳入 Watcher 內(nèi)部的 getter 方法。
new Watcher(vm, updateComponent);

// 7. new Watcher 會(huì)執(zhí)行 Watcher.get 方法
// 8. Watcher.get 會(huì)執(zhí)行 this.getter.call(vm, vm) ,也就是執(zhí)行 updateComponent 方法
// 9. updateComponent 會(huì)執(zhí)行 vm._update(vm._render())

// 10. 調(diào)用 vm._render 生成虛擬 dom
Vue.prototype._render = function (): VNode {
  const vm: Component = this;
  const { render } = vm.$options;
  let vnode = render.call(vm._renderProxy, vm.$createElement);
  return vnode;
};
// 11. 調(diào)用 vm._update(vnode) 渲染虛擬 dom
Vue.prototype._update = function (vnode: VNode) {
  const vm: Component = this;
  if (!prevVnode) {
	// 初次渲染
	vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false);
  } else {
	// 更新
	vm.$el = vm.__patch__(prevVnode, vnode);
  }
};
// 12. vm.__patch__ 方法就是做的 dom diff 比較,然后更新 dom,這里就不展開了。

"""
看完 Vue 模板渲染的過程,我們可以得到如下的流程圖:


圖解 Vue 響應(yīng)式原理


到這里,我們就知道了 Watcher 其實(shí)是在 Vue 初始

化的階段創(chuàng)建的,屬于生命周期中 beforeMount 的

位置創(chuàng)建的,創(chuàng)建 Watcher 時(shí)會(huì)執(zhí)行 render 方法,

最終將 Vue 代碼渲染成真實(shí)的 DOM。

我們?cè)賹⒅暗牧鞒陶弦幌拢湍艿玫揭韵碌牧鞒蹋?/p>

圖解 Vue 響應(yīng)式原理


上圖分析了 Vue 初始化到渲染 DOM 的整個(gè)過程,最后我們?cè)俜治鲆?/p>

下,當(dāng)數(shù)據(jù)變化時(shí),Vue 又是怎么進(jìn)行更新的?

其實(shí),在上圖也能看出,在 Data 變化時(shí),會(huì)調(diào)用 Dep.notify 方法,隨

即調(diào)用 Watcher 內(nèi)部的 update 方法,此方法會(huì)將所有使用到這個(gè) Data

的 Watcher 加入一個(gè)隊(duì)列,并開啟一個(gè)異步隊(duì)列進(jìn)行更新,最終執(zhí)行

_render 方法完成頁面更新。

整體的流程如下:


圖解 Vue 響應(yīng)式原理


好了,探索到這里,Vue 的響應(yīng)式原理,已經(jīng)被我們分析透徹了,如果你

還沒有明白,不妨再細(xì)品一下上圖。

組件渲染

本來探索到上面的流程圖就結(jié)束了,但好奇的我又想到了一個(gè)問題 ??

Vue 組件又是怎么渲染的呢?

帶著這個(gè)問題,我繼續(xù)查閱了源碼。
"""

// 從模板編譯開始,當(dāng)發(fā)現(xiàn)一個(gè)自定義組件時(shí),會(huì)執(zhí)行以下函數(shù)
// 1. compileToFunctions(template)
// 2. compile(template, options);
// 3. const ast = parse(template.trim(), options)
// 4. const code = generate(ast, options)
// 5. createElement

// 6. createComponent
export function createComponent(
  Ctor: Class<Component> | Function | Object | void,
  data: ?VNodeData,
  context: Component,
  children: ?Array<VNode>,
  tag?: string
): VNode | Array<VNode> | void {
  // $options._base 其實(shí)就是全局 Vue 構(gòu)造函數(shù),在初始化時(shí) initGlobalAPI 中定義的:Vue.options._base = Vue
  const baseCtor = context.$options._base;
  // Ctor 就是 Vue 組件中 <script> 標(biāo)簽下 export 出的對(duì)象
  if (isObject(Ctor)) {
	// 將組件中 export 出的對(duì)象,繼承自 Vue,得到一個(gè)構(gòu)造函數(shù)
	// 相當(dāng)于 Vue.extend(YourComponent)
	Ctor = baseCtor.extend(Ctor);
  }
  const vnode = new VNode(`vue-component-${Ctor.cid}xxx`);
  return vnode;
}

// 7. 實(shí)現(xiàn)組件繼承 Vue,并調(diào)用 Vue._init 方法,進(jìn)行初始化
Vue.extend = function (extendOptions: Object): Function {
  const Super = this;
  const Sub = function VueComponent(options) {
	// 調(diào)用 Vue.prototype._init,之后的流程就和首次加載保持一致
	this._init(options);
  };
  // 原型繼承,相當(dāng)于:Component extends Vue
  Sub.prototype = Object.create(Super.prototype);
  Sub.prototype.constructor = Sub;
  return Sub;
};

"""


看完組件渲染的源碼后,結(jié)合上文,重新整理了一張流程圖,圖中的藍(lán)色

部分就是渲染組件的過程。


圖解 Vue 響應(yīng)式原理



好了,現(xiàn)在是真的結(jié)束了,最終的流程圖就是上面的這一張圖。

問個(gè)問題,現(xiàn)在你理解 Vue 響應(yīng)式原理了嗎?

如果仍覺得不好理解,我這里還準(zhǔn)備了一張帶標(biāo)注的簡(jiǎn)圖 ??


圖解 Vue 響應(yīng)式原理


思考與總結(jié)

本文從源碼的角度,介紹了 Vue 響應(yīng)式原理,來簡(jiǎn)單回顧一下吧。

  • 從 new Vue 開始,首先通過 get、set 監(jiān)聽 Data 中的數(shù)據(jù)變化,同時(shí)創(chuàng)建 Dep 用來搜集使用該 Data 的 Watcher。

  • 編譯模板,創(chuàng)建 Watcher,并將 Dep.target 標(biāo)識(shí)為當(dāng)前 Watcher。

  • 編譯模板時(shí),如果使用到了 Data 中的數(shù)據(jù),就會(huì)觸發(fā) Data 的 get 方法,然后調(diào)用 Dep.addSub 將 Watcher 搜集起來。

  • 數(shù)據(jù)更新時(shí),會(huì)觸發(fā) Data 的 set 方法,然后調(diào)用 Dep.notify 通知所有使用到該 Data 的 Watcher 去更新 DOM。文章來源地址http://www.zghlxwxcb.cn/news/detail-597708.html

到了這里,關(guān)于圖解 Vue 響應(yīng)式原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue3 數(shù)據(jù)響應(yīng)式原理

    核心: 通過Proxy(代理): 攔截對(duì)data任意屬性的任意(13種)操作, 包括屬性值的讀寫, 屬性的添加, 屬性的刪除等… 通過 Reflect(反射): 動(dòng)態(tài)對(duì)被代理對(duì)象的相應(yīng)屬性進(jìn)行特定的操作 Vue3的響應(yīng)式比Vue2好在哪里? 效率更高了,Vue2中假設(shè)監(jiān)聽某個(gè)對(duì)象,該對(duì)象中有一萬個(gè)屬性,他要循

    2024年02月11日
    瀏覽(20)
  • Vue源碼學(xué)習(xí) - 數(shù)據(jù)響應(yīng)式原理

    Vue源碼學(xué)習(xí) - 數(shù)據(jù)響應(yīng)式原理

    Vue.Js的核心包括一套 “響應(yīng)式系統(tǒng)”?!绊憫?yīng)式”,是指當(dāng)數(shù)據(jù)改變后,Vue會(huì)通知到使用該數(shù)據(jù)的代碼。例如,視圖渲染中使用了數(shù)據(jù),數(shù)據(jù)改變后,視圖也會(huì)自動(dòng)更新。 vue2.X的數(shù)據(jù)響應(yīng)式是利用 Object.defineProperty() 實(shí)現(xiàn)的,通過定義對(duì)象屬性 getter/setter 攔截對(duì)屬性的獲取和

    2024年02月15日
    瀏覽(23)
  • 深入理解Vue的響應(yīng)式原理

    用過Vue這個(gè)框架的人應(yīng)該都知道,數(shù)據(jù)驅(qū)動(dòng)是Vue框架的核心,數(shù)據(jù)雙向綁定是它的一大特色,根據(jù)官方的解釋,我們可以比較清晰地去知道響應(yīng)式的簡(jiǎn)單原理。 當(dāng)你把一個(gè)普通的 JavaScript 對(duì)象傳入 Vue 實(shí)例作為 data 選項(xiàng),Vue 將遍歷此對(duì)象所有的 property,并使用 Object.definePro

    2023年04月17日
    瀏覽(17)
  • 手寫Vue3響應(yīng)式數(shù)據(jù)原理

    手寫Vue3響應(yīng)式數(shù)據(jù)原理

    我們想要對(duì)一個(gè)對(duì)象數(shù)據(jù)進(jìn)行處理,從而實(shí)現(xiàn)更改dom。但如何更改對(duì)一個(gè)對(duì)象數(shù)據(jù)進(jìn)行更改呢? vue2 的雙向數(shù)據(jù)綁定是利?ES5 的?個(gè) API ,Object.defineProperty()對(duì)數(shù)據(jù)進(jìn)?劫持 結(jié)合 發(fā)布訂閱模式的?式來實(shí)現(xiàn)的。 vue3 中使?了 ES6 的 ProxyAPI 對(duì)數(shù)據(jù)代理,通過 reactive() 函數(shù)給每?

    2024年02月11日
    瀏覽(19)
  • 學(xué)習(xí)Vue:響應(yīng)式原理與性能優(yōu)化策略

    性能優(yōu)化是Vue.js應(yīng)用開發(fā)中的一個(gè)關(guān)鍵方面,而深入了解響應(yīng)式原理并采用有效的性能優(yōu)化策略可以顯著提升應(yīng)用的性能。本文將解釋響應(yīng)式原理并介紹一些性能優(yōu)化策略,旨在幫助您構(gòu)建高性能的Vue.js應(yīng)用。 Vue.js的響應(yīng)式原理是通過利用 Object.defineProperty 或 Proxy 來追蹤數(shù)據(jù)

    2024年02月11日
    瀏覽(29)
  • Vue.js 2.0 深入響應(yīng)式原理

    Vue.js 2.0 深入響應(yīng)式原理

    大部分的基礎(chǔ)內(nèi)容我們已經(jīng)講到了,現(xiàn)在講點(diǎn)底層內(nèi)容。Vue 最顯著的一個(gè)功能是響應(yīng)系統(tǒng) —— 模型只是普通對(duì)象,修改它則更新視圖。這會(huì)讓狀態(tài)管理變得非常簡(jiǎn)單且直觀,不過理解它的原理以避免一些常見的陷阱也是很重要的。在本節(jié)中,我們將開始深挖 Vue 響應(yīng)系統(tǒng)的

    2023年04月11日
    瀏覽(21)
  • Vue3.0中的響應(yīng)式原理

    Vue3.0中的響應(yīng)式原理

    實(shí)現(xiàn)原理: - 對(duì)象類型:通過 ``Object.defineProperty()``對(duì)屬性的讀取、修改進(jìn)行攔截(數(shù)據(jù)劫持)。 - 數(shù)組類型:通過重寫更新數(shù)組的一系列方法來實(shí)現(xiàn)攔截。(對(duì)數(shù)組的變更方法進(jìn)行了包裹)。 存在問題: - 新增屬性、刪除屬性, 界面不會(huì)更新。 - 直接通過下標(biāo)修改數(shù)組, 界面

    2023年04月17日
    瀏覽(25)
  • 比較react和vue的響應(yīng)式原理

    React 和 Vue 都使用虛擬 DOM 來提高性能,但在響應(yīng)式原理和狀態(tài)管理方面有一些不同。React 更注重單向數(shù)據(jù)流和手動(dòng)狀態(tài)管理,而 Vue 強(qiáng)調(diào)響應(yīng)式數(shù)據(jù)綁定和自動(dòng)狀態(tài)追蹤,使開發(fā)更加便捷。 React的響應(yīng)式原理: 虛擬 DOM和單向數(shù)據(jù)流 :React 使用虛擬 DOM(Virtual DOM)來管理和渲

    2024年02月07日
    瀏覽(18)
  • 【Vue3響應(yīng)式原理#01】Reactivity

    【Vue3響應(yīng)式原理#01】Reactivity

    專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項(xiàng)目專欄,硬核??推薦?? 歡迎各位ITer關(guān)注點(diǎn)贊收藏?????? 以下是柏成根據(jù)Vue3官方課程整理的響應(yīng)式書面文檔 - 第一節(jié),課程鏈接在此:Vue 3 Reactivity - Vue 3 Reactivity | Vue Mastery,本文檔可作為課程的輔助材料,

    2024年02月08日
    瀏覽(17)
  • Vue2.0 的響應(yīng)式原理 私

    Vue2.0 的響應(yīng)式原理 私

    使用的Object.defineProperty()重新定義對(duì)象,給data的每個(gè)屬性都添加了getter和setter方法。這時(shí)候會(huì)為對(duì)象的每個(gè)屬性創(chuàng)建一個(gè)Dep實(shí)例? (依賴)。Dep實(shí)例可以訂閱和通知相關(guān)的Watcher實(shí)例。,? 這一步叫? 數(shù)據(jù)劫持? 或者 依賴收集 在數(shù)據(jù)發(fā)生更新后調(diào)用 set 時(shí)會(huì)通知發(fā)布者 notify

    2024年02月11日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包