整體分析Vue的基本結構如下圖所示:(備注:完整代碼github地址https://github.com/1512955040/MiniVue)


上圖中,為我們模擬最小vue的整體結構,首先創建一個vue類型,它負責把data中的成員注入到vue實例中,並且轉化成getter/setter,observer的作用是數據劫持,對data中的屬性進行數據監聽,如果數據發生變化會獲取到最新的值,並通知dep。Compiler的作用是解析每個元素中的指令和差值錶達式並替換成相應的數據。Dep的作用是添加觀察者,當數據發生變化時通知所有的觀察者。Watcher內部有一個Update方法負責更新視圖,下面我們用代碼的方式一一進行實現。

1.Vue.js功能:

1-1負責接收初始化的參數(選項)

1-2負責把data中的屬性注入到vue實例,轉化成getter/setter

1-3負責調用observer監聽data中所有屬性的變化

1-4負責調用Compiler解析指令/差值錶達式

類圖結構如下:

如上圖所示:vue類中有三個屬性,分別是$options,$el,$data,這三個屬性記錄構造函數中傳過來的參數。_proxyData為vue類中的方法

所以以_開頭的成員就是私有成員,這個方法的功能是把data中的屬性轉化為getter和setter注入到vue實例中。

class Vue{
constructor(options) {
//1.通過屬性保存選項中的數據
this.$options = options || {}
this.$data = options.data || {}
this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el
//2.把data中的成員轉化為getter和setter,注入到vue實例中
this._proxyData(this.$data)
//3.調用observer對象,監聽數據的變化
new Observer(this.$data)
//4.調用compiler對象,解析指令和差值錶達式
new Compiler(this)
}
//把Vue的屬性轉化為getter和setter,注入到Vue實例中
_proxyData(data){
//遍曆data中所有屬性
Object.keys(data).forEach(key=>{
//把data的屬性注入到vue實例全局中
Object.defineProperty(this,key,{
enumerable:true,
configurable:true,
get(){
return data[key]
},
set(newValue){
if(newValue===data[key]){
return
}
data[key]=newValue
}
})
})
}
}

2.Observer.js功能(數據劫持):

2-1 負責把data選項中的屬性轉化為響應式數據

2-2 data中的某個屬性也是對象,把該屬性轉化為響應式數據

2-3 數據變化發送通知

類圖結構如下:

如上圖所示:

walk方法的作用是遍曆data中的所有屬性,defineReactive是定義響應式數據,也就是通過調用defineReactive方法把屬性轉化為getter和setter。

class Observer{
constructor(data) {
this.walk(data)
}
//walk方法遍曆data中的所有屬性
walk(data) {
//1.判斷data是否對象
if(!data || typeof data !=='object'){
return
}
//2.遍曆data對象的所有屬性
Object.keys(data).forEach(key=>{
this.defineReactive(data,key,data[key])
})
}
//degineReactivce方法定義響應式數據 把屬性轉化為getter和setter
defineReactive(obj,key,val) {
let that=this
// 負責收集依賴,並發送通知
let dep=new Dep()
//如果val傳入對象的話也給對象裏面的屬性添加getter和setter方法
this.walk(val)
Object.defineProperty(obj,key,{
enumerable:true,
configurable:true,
get(){
// 收集依賴
Dep.target && dep.addSub(Dep.target)
return val
},
set(newValue){
if(newValue==val){
return
}
val=newValue
//如果給屬性重新賦值成對象,給對象裏面的屬性重新添加getter和setter方法
//比如:曆史數據vm.msg="Hello World" 修改之後vm.msg={a:'Hwllo World'}
//再次調用此方法給vm.msg.a重新添加getter和setter方法
that.walk(newValue)
//發送通知
dep.notify()
}
})
}
}

3.Compiler.js功能:

3-1 負責編譯模板,解析指令/差值錶達式

3-2 負責頁面的首次渲染

3-3 當數據變化後重新渲染視圖

類圖結構如下:

如上圖所示:

el為構造函數傳過來的options.el,vm是vue的實例,下面都是vm的方法,對DOM進行操作。compile方法內部遍曆dom對象的所有節點,並且

判斷這些節點是文本節點,如果是文本節點解析差值錶達式,如果是元素節點解析指令,isTextNode和isElementNode方法判斷是文本節點還

是元素節點。compileElement和compileText方法解析差值錶達式和指令。isDirective這個方法判斷元素屬性是否是指令。

4.Dep.js功能:

4-1 收集依賴,添加觀察者(watcher)

4-2 通知所有觀察者

如上圖所示:

在vue的響應式機制中,使用觀察者模式來響應數據的變化,Dep的作用是收集依賴,在getter方法中收集依賴,在setter方法中通知依賴,每

一個響應式的屬性都會場景一個Dep對象,負責收集所有依賴於該屬性的地方,所有依賴於該屬性的比特置都會創建一個watcher對象,所以

Dep就是收集於該屬性的watcher對象,使用setter方法去通知依賴,當屬性發生變化時調用nodify方法去發送通知,然後調用watcher對象

的update方法。

類的機構如下圖:

如上圖所示:

subs是一個數組,存儲dep中所有的watcher,addSub方法添加watcher,notify方法發布通知

class Dep{
constructor() {
//存儲所有的觀察者
this.subs=[]
}
// 添加觀察者
addSub(sub){
if(sub && sub.update) {
this.subs.push(sub)
}
}
//發送通知
notify(){
this.subs.forEach(sub =>{
sub.update()
})
}
}

5.Watcher.js功能:

5-1 當數據變化觸發依賴,dep通知所有的Watcher實例更新視圖

5-2 自身實例化的時候往dep對象中添加自己

如上圖所示:

data中的每一個屬性都要創建一個Dep對象, 在收集依賴的時候把所有對象的watcher添加到dep對象的subs數組中,在setter對象中發送通

知,調用Dep對象的notify方法通知所有關聯的watcher對象更新視圖。

類圖結構如下:

如上圖所示:

update對象更新視圖,cb回調函數,指明如何更新視圖。在更新視圖的時候需要一個屬性key(data中的屬性名稱),oldvalue是key 對應的值。

class Watcher{
constructor(vm,key,cb) {
this.vm=vm
//data中的屬性名稱
this.key=key
//回調函數負責更新視圖
this.cb=cb
//把watcher對象記錄到Dep類的靜態屬性target
Dep.target =this
//觸發get方法,在get方法中會調用addSub
this.oldValue=vm[key]
Dep.target=null
}
//當數據發生變化時更新視圖
update(){
let newValue=this.vm[this.key]
if(this.oldValue === newValue){
return
}
this.cb(newValue)
}
}

下面通過這張圖作整體流程的總結:

Vue響應式原理底層代碼模擬實現的更多相關文章

  1. 詳解Vue響應式原理

    摘要: 搞懂Vue響應式原理! 作者:浪裏行舟 原文:深入淺出Vue響應式原理 Fundebug經授權轉載,版權歸原作者所有. 前言 Vue 最獨特的特性之一,是其非侵入性的響應式系統.數據模型僅僅是 ...

  2. 深度解析 Vue 響應式原理

    深度解析 Vue 響應式原理 該文章內容節選自團隊的開源項目 InterviewMap.項目目前內容包含了 JS.網絡.瀏覽器相關.性能優化.安全.框架.Git.數據結構.算法等內容,無論是基礎還是進 ...

  3. Vue源碼--解讀vue響應式原理

    原文鏈接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方說明裏有深入響應式原理這一節.在此官方也提到過: 當你把一個普通的 ...

  4. vue響應式原理,去掉優化,只看核心

    Vue響應式原理 作為寫業務的碼農,幾乎不必知道原理.但是當你去找工作的時候,可是需要造原子彈的,什麼都得知道一些才行.所以找工作之前可以先複習下,只要是關於vue的,必定會問響應式原理. 核心: / ...

  5. 深入Vue響應式原理

    深入Vue.js響應式原理 一.創建一個Vue應用 new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h =& ...

  6. vue響應式原理解析

    # Vue響應式原理解析 首先定義了四個核心的js文件 - 1. observer.js 觀察者函數,用來設置data的get和set函數,並且把watcher存放在dep中 - 2. watcher ...

  7. 深入解析vue響應式原理

    摘要:本文主要通過結合vue官方文檔及源碼,對vue響應式原理進行深入分析. 1.定義 作為vue最獨特的特性,響應式可以說是vue的靈魂了,錶面上看就是數據發生變化後,對應的界面會重新渲染,那麼響應 ...

  8. 淺析Vue響應式原理(三)

    Vue響應式原理之defineReactive defineReactive 不論如何,最終響應式數據都要通過defineReactive來實現,實際要借助ES5新增的Object.definePro ...

  9. Vue響應式原理及總結

    Vue 的響應式原理是核心是通過 ES5 的保護對象的 Object.defindeProperty 中的訪問器屬性中的 get 和 set 方法,data 中聲明的屬性都被添加了訪問器屬性,當讀取 ...

  10. 深入探討vue響應式原理

    現在是時候深入一下了!Vue 最獨特的特性之一,是其非侵入性的響應式系統.數據模型僅僅是普通的 JavaScript 對象.而當你修改它們時,視圖會進行更新.這使得狀態管理非常簡單直接,不過理解其工作 ...

隨機推薦

  1. 【MSP是什麼】MSP認證之項目集與項目群的關系和區別

    項目群和項目集都是一個意思,翻譯時沒有統一口徑造成的.只要能與項目組合區別開就可以了. 項目集與項目群的區別,不在於那些項目自身,而在於管理者的思想,管理者對待項目的態度.項目集與項目群,首先都是多個 ...

  2. I.MX6 wm8962 0-001a: DC servo timed out

    /******************************************************************************* * I.MX6 wm8962 0-00 ...

  3. LeetCode Lowest Common Ancestor of a Binary Search Tree (LCA最近公共祖先)

    題意: 給一棵二叉排序樹,找p和q的LCA. 思路: 給的是BST(無相同節點),那麼每個節點肯定大於左子樹中的最大,小於右子樹種的最小.根據這個特性,找LCA就簡單多了. 分三種情况: (1)p和q ...

  4. POJ 2481-Cows(BIT)

    題意: n個牛,每個牛對應一個區間,對於每個牛求n個區間有幾個包含該牛的區間. 分析: 先 區間右邊界從大到小排序,相同時左邊界小到大,統計第i頭牛即左邊界在前i-1頭左邊界的正序數. #includ ...

  5. RTCP

    RTCP RTCP協議將控制包周期發送給所有連接者,應用與數據包相同的分發機制.低層協議提供數據與控制包的複用,如使用單獨的UDP端口號.RTCP執行下列四大功能: (1) 主要是提供數據發布的質量反 ...

  6. cos-26上傳

    在開發中常常需要上傳文件,上傳文件的方式有很多種,這裏有一個cos實現的例子. 首先是要拷貝cos.jar包拷貝到WEB-INF/lib目錄下,然後才進行編碼. 創建一個可以進行自動重命名的Java文 ...

  7. PreTranslateMessage和TranslateMessage區別(轉)

    PreTranslateMessage是消息在送給TranslateMessage函數之前被調用的,絕大多數本窗口的消息都要通過這裏,比較常用,當需要在MFC之前處理某些消息時,常常要在這裏添加代碼. ...

  8. Linux內核導出符號宏定義EXPORT_SYMBOL源代碼分析

    資源: <include/linux/moudule.h> --. #ifndef MODULE_SYMBOL_PREFIX #define MODULE_SYMBOL_PREFIX &q ...

  9. 解决 ASP.NET Core MySql varchar 字符串截取(長度 255)

    ASP.NET Core 中使用 MySql,如果字段類型為varchar,不管設置多少長度,插入或更新數據的時候,會自動截斷(截取 255 長度的字符). 出現問題的原因,就是使用了MySql.Da ...

  10. jQuery中對未來的元素綁定事件用 on

    最近項目需要點擊彈窗裏面的a標簽出現外連接跳轉提示 <a href="javascript:void(0);" target="_blank" id=&q ...