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

數(shù)據(jù)驅(qū)動(dòng)

在我們學(xué)習(xí)Vue.js的過(guò)程中蒜绽,我們經(jīng)橙焓担看到三個(gè)概念

  • 數(shù)據(jù)驅(qū)動(dòng)
  • 數(shù)據(jù)響應(yīng)式
  • 雙向數(shù)據(jù)綁定

核心原理分析

  • Vue 2.x版本與Vue 3.x版本的響應(yīng)式實(shí)現(xiàn)有所不同郊丛,我們可以進(jìn)行分別講解
    • Vue 2.x響應(yīng)式基于ES5的Object.defineProperty實(shí)現(xiàn)
    • Vue 3.x響應(yīng)式基于ES6的Proxy實(shí)現(xiàn)

回顧defineProperty

我們先定義一個(gè)對(duì)象

    var obj = {
      name: 'willam',
      age: 18
    }

在defineProperty中念赶,第一個(gè)參數(shù)為需要進(jìn)行操作的對(duì)象忆绰,第二個(gè)參數(shù)為屬性闸与,第三個(gè)為對(duì)應(yīng)的操作

    Object.defineProperty(obj, 'gender', {
      // 值
      value: '男',
      // 是否可寫
      writable: true,
      // 控制是否可以枚舉(遍歷
      enumerable: true,
      // 本次定義之后毙替,再次進(jìn)行重新配置
      configurable: true
    })

    Object.defineProperty(obj, 'gender', {
      enumerable: false
    })

解釋一下代碼:
賦予值:value
是否可以編輯:writable(這條屬性默認(rèn)值為false,表示只可以讀践樱,不可以寫入)


如圖厂画,打印結(jié)果并未發(fā)生改變

是否可以枚舉(遍歷):enumerable(這條屬性默認(rèn)值也為false)

    for (var k in obj) {
      console.log(k, obj[k])
    }
在遍歷中,如果設(shè)置的是false值拷邢,我們是無(wú)法讀取到他的值的

在本次定義之后袱院,可否再次進(jìn)行重新配置:configurable:默認(rèn)值為false,true時(shí)可以進(jìn)行再次的配置

false值瞭稼,再次進(jìn)行配置會(huì)報(bào)錯(cuò)

進(jìn)行屬性操作時(shí)忽洛,可以通過(guò)getter,setter實(shí)現(xiàn)环肘,訪問(wèn)器和設(shè)置器欲虚,在訪問(wèn)和設(shè)置時(shí)進(jìn)行相應(yīng)的功能設(shè)置
value,writable和get悔雹,set無(wú)法共存复哆,邏輯沖突
getter指的是:
當(dāng)我們?cè)L問(wèn)對(duì)象的屬性時(shí),會(huì)執(zhí)行這個(gè)函數(shù)

    Object.defineProperty(obj, 'gender', {
      get () {
        // 甚至可以進(jìn)行額外的操作
        console.log('任意需要的自定義操作')
        return '男'
      },
屬性訪問(wèn)時(shí)也可以設(shè)置一個(gè)事件

setter指的是:
當(dāng)我們?cè)O(shè)置某個(gè)屬性時(shí)觸發(fā)的函數(shù)

      set (newValue) {
        console.log('新的值是',newValue)
        this.gender = newValue
      }

這樣寫是一個(gè)誤區(qū)腌零,設(shè)置時(shí)觸發(fā)setter梯找,就會(huì)造成遞歸


造成溢出

解決辦法:
通過(guò)第三方數(shù)據(jù),來(lái)存取數(shù)據(jù)

    var genderValue = '男'
    Object.defineProperty(obj, 'gender', {
      get () {
        console.log('任意需要的自定義操作')
        return genderValue
      },
      set (newValue) {
        console.log('新的值是',newValue)
        genderValue = newValue
      }
    })
解決問(wèn)題

模擬Vue2響應(yīng)式原理

  • Vue2.x的數(shù)據(jù)響應(yīng)式就是由Object.defineProperty()實(shí)現(xiàn)的
    • 設(shè)置data之后益涧,遍歷所有的屬性锈锤,轉(zhuǎn)換為getter和setter,從而在數(shù)據(jù)變化時(shí)進(jìn)行視圖更新操作

我們來(lái)寫寫模擬代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">原始內(nèi)容</div>
  <script>
    // 聲明一個(gè)對(duì)象用于進(jìn)行數(shù)據(jù)存儲(chǔ)
    let data = {
      msg: 'hello'
    }
    // 模擬一個(gè)vue實(shí)例
    let vm = {}
    // 通過(guò)數(shù)據(jù)劫持的方式,將data的屬性設(shè)置給getter與setter久免,并且設(shè)置給vm
    Object.defineProperty(vm, 'msg', {
      // 可遍歷
      enumerable: true,
      // 可配置
      configurable: true,
      // get方法
      get () {
        console.log('訪問(wèn)數(shù)據(jù)')
        return data.msg
      },
      // set方法
      set (newValue) {
        // 更新數(shù)據(jù)
        data.msg = newValue
        // 數(shù)據(jù)更改浅辙,更新視圖中DOM元素內(nèi)容
        document.querySelector('#app').textContent = data.msg
      }
    })
  </script>
</body>
</html>

解釋一下代碼,vm的作用就是通過(guò)數(shù)據(jù)劫持將data中的數(shù)據(jù)設(shè)置給get與set妄壶,并且設(shè)置給vm摔握,最后更改的還是data


改進(jìn)

  • 操作中只監(jiān)聽(tīng)了一個(gè)屬性寄狼,多個(gè)屬性無(wú)法處理
  • 無(wú)法監(jiān)聽(tīng)數(shù)組變化(Vue里也是同樣存在這個(gè)問(wèn)題)
  • 無(wú)法處理屬性也為對(duì)象的情況

處理多個(gè)屬性的情況

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">原始內(nèi)容</div>
  <script>
    // 聲明一個(gè)對(duì)象用于進(jìn)行數(shù)據(jù)存儲(chǔ)
    let data = {
      msg1: 'hello',
      msg2: 'world'
    }
    // 模擬一個(gè)vue實(shí)例
    let vm = {}
    Object.keys(data).forEach(key => {
      // 通過(guò)數(shù)據(jù)劫持的方式丁寄,將data的屬性設(shè)置給getter與setter,并且設(shè)置給vm
      Object.defineProperty(vm, key, {
        enumerable: true,
        configurable: true,
        // get方法
        get () {
          console.log('訪問(wèn)數(shù)據(jù)')
          return data[key]
        },
        // set方法
        set (newValue) {
          // 更新數(shù)據(jù)
          data[key] = newValue
          // 數(shù)據(jù)更改泊愧,更新視圖中DOM元素內(nèi)容
          document.querySelector('#app').textContent = data[key]
        }
      })
    })
  </script>
</body>
</html>

這里我們使用到了Object.keys()方法伊磺,該方法可以返回一個(gè)由內(nèi)部參數(shù)對(duì)象的自身可枚舉屬性構(gòu)成的一個(gè)數(shù)組,然后我們?cè)賹⑵溥M(jìn)行forEach遍歷删咱,得到每一個(gè)屬性屑埋,然后進(jìn)行多個(gè)屬性的處理,詳細(xì)邏輯可以通過(guò)代碼看的一清二楚

檢測(cè)數(shù)組的方法

對(duì)數(shù)組的操作是無(wú)法實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)實(shí)現(xiàn)的
Vue通過(guò)特定的方法處理可以解決這種問(wèn)題

  • 添加數(shù)組方法支持:
   const arrMethodName = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
  • 準(zhǔn)備一個(gè)用于存儲(chǔ)處理結(jié)果的對(duì)象痰滋,準(zhǔn)備替換掉數(shù)組屬性的原型指針
    // 存儲(chǔ)處理結(jié)果的對(duì)象摘能,準(zhǔn)備替換到數(shù)組數(shù)組實(shí)例的原型指針 _proto_
    const customProto = {}
  • 為了確保原始功能能夠被使用
        // 確保原始功能可以使用,this為數(shù)組實(shí)例
        const result = Array.prototype[method].apply(this, arguments)
  • 進(jìn)行其他自定義設(shè)置,比如更新視圖
        // 進(jìn)行其他自定義功能設(shè)置敲街,比如团搞,更新視圖
        document.querySelector('#app').textContent = this
        return result
  • 為了避免數(shù)組實(shí)例無(wú)法再使用我們處理的方法以外的方法:
    // 為了避免數(shù)組實(shí)例無(wú)法再使用其他的數(shù)組方法
    customProto.__proto__ = Array.prototype
  • 那么如何將這些設(shè)置與攔截寫在一起呢?
    答案很簡(jiǎn)單:判斷一下就行了

    完整代碼
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">原始內(nèi)容</div>
  <script>
    // 聲明一個(gè)對(duì)象用于進(jìn)行數(shù)據(jù)存儲(chǔ)
    let data = {
      msg1: 'hello',
      msg2: 'world',
      arr: [1, 2, 3]
    }
    // 模擬一個(gè)vue實(shí)例
    let vm = {}

    // 添加數(shù)組方法的支持
    const arrMethodName = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']

    // 存儲(chǔ)處理結(jié)果的對(duì)象多艇,準(zhǔn)備替換到數(shù)組數(shù)組實(shí)例的原型指針 _proto_
    const customProto = {}

    // 為了避免數(shù)組實(shí)例無(wú)法再使用其他的數(shù)組方法
    customProto.__proto__ = Array.prototype

    arrMethodName.forEach(method => {
      customProto[method] = function () {
        // 確保原始功能可以使用,this為數(shù)組實(shí)例
        const result = Array.prototype[method].apply(this, arguments)
        
        // 進(jìn)行其他自定義功能設(shè)置逻恐,比如,更新視圖
        document.querySelector('#app').textContent = this
        return result
      }
    })

    Object.keys(data).forEach(key => {
      // 檢測(cè)是否為數(shù)組峻黍,是的話單獨(dú)處理
      if (Array.isArray(data[key])) {
        // 將當(dāng)前數(shù)組實(shí)例的__proto__更換為customProto就行了
        data[key].__proto__ = customProto
      }

      // 通過(guò)數(shù)據(jù)劫持的方式复隆,將data的屬性設(shè)置給getter與setter,并且設(shè)置給vm
      Object.defineProperty(vm, key, {
        enumerable: true,
        configurable: true,
        // get方法
        get () {
          console.log('訪問(wèn)數(shù)據(jù)')
          return data[key]
        },
        // set方法
        set (newValue) {
          // 更新數(shù)據(jù)
          data[key] = newValue
          // 數(shù)據(jù)更改姆涩,更新視圖中DOM元素內(nèi)容
          document.querySelector('#app').textContent = data[key]
        }
      })
    })
  </script>
</body>
</html>

改進(jìn):封裝與遞歸

使用立即執(zhí)行函數(shù)挽拂,全部包裹起來(lái),如果對(duì)象內(nèi)部還含有對(duì)象的話就進(jìn)行遞歸處理骨饿,很簡(jiǎn)單的邏輯:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">原始內(nèi)容</div>
  <script>
    // 聲明數(shù)據(jù)對(duì)象亏栈,模擬 Vue 實(shí)例的 data 屬性
    let data = {
      msg1: 'hello',
      msg2: 'world',
      arr: [1, 2, 3],
      obj: {
        name: 'jack',
        age: 18
      }
    }
    // 模擬 Vue 實(shí)例的對(duì)象
    let vm = {}

    // 封裝為函數(shù),用于對(duì)數(shù)據(jù)進(jìn)行響應(yīng)式處理
    const createReactive = (function () {
      const arrMethodName = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
      const customProto = {}
      customProto.__proto__ = Array.prototype
      arrMethodName.forEach(method => {
        customProto[method] = function () {
          const result = Array.prototype[method].apply(this, arguments)
          document.querySelector('#app').textContent = this
          return result
        }
      })

      // 需要進(jìn)行數(shù)據(jù)劫持的主體功能样刷,也是遞歸時(shí)需要的功能
      return function (data, vm) {
        // 遍歷被劫持對(duì)象的所有屬性
        Object.keys(data).forEach(key => {
          // 檢測(cè)是否為數(shù)組
          if (Array.isArray(data[key])) {
            // 將當(dāng)前數(shù)組實(shí)例的 __proto__ 更換為 customProto 即可
            data[key].__proto__ = customProto
          } else if (typeof data[key] === 'object' && data[key] !== null) {
            // 檢測(cè)是否為對(duì)象仑扑,如果為對(duì)象,進(jìn)行遞歸操作
            vm[key] = {}
            createReactive(data[key], vm[key])
            return
          }

          // 通過(guò)數(shù)據(jù)劫持的方式置鼻,將 data 的屬性設(shè)置為 getter/setter
          Object.defineProperty(vm, key, {
            enumerable: true,
            configurable: true,
            get () {
              console.log('訪問(wèn)了屬性')
              return data[key]
            },
            set (newValue) {
              // 更新數(shù)據(jù)
              data[key] = newValue
              // 數(shù)據(jù)更改镇饮,更新視圖中 DOM 元素的內(nèi)容
              document.querySelector('#app').textContent = data[key]
            }
          })
        })
      }

    })()
  
    createReactive(data, vm)
  </script>
</body>
</html>

這就是Vue2版本的響應(yīng)式原理分析

回顧Proxy

ES6提供的一個(gè)功能,對(duì)一個(gè)對(duì)象提供代理操作

  <script>
    const data = {
      msg1: '內(nèi)容',
      arr: [1, 2, 3],
      obj: {
        name: 'willam',
        age: 19
      }
    }
    
    const P = new Proxy(data, {
      get (target, property, receiver) {
        console.log(target, property, receiver)
        return target[property]
      },
      set (target, property, value, receiver) {
        console.log(target, property, value, receiver)
        target[property] = value
      }
    })
  </script>

通過(guò)代理箕母,訪問(wèn)P也就是訪問(wèn)了data的代理储藐,同樣的數(shù)據(jù)俱济,get方法中,target參數(shù)表示原數(shù)據(jù)data钙勃,property表示訪問(wèn)的哪條屬性蛛碌,receiver表示通過(guò)代理之后的數(shù)據(jù)
set方法中新添了一個(gè)value參數(shù),表示當(dāng)前設(shè)置的數(shù)值
我們來(lái)通過(guò)控制臺(tái)打印一探究竟


Vue3響應(yīng)式原理

與2版本的區(qū)別為數(shù)據(jù)響應(yīng)式是Proxy實(shí)現(xiàn)的辖源,其他相同蔚携,接下來(lái)進(jìn)行演示

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">原始內(nèi)容</div>
  <script>
    const data = {
      msg1: '內(nèi)容',
      arr: [1, 2, 3],
      content: 'world',
      obj: {
        name: 'willam',
        age: 19
      }
    }

    const vm = new Proxy(data, {
      get (target, key) {
        return target[key]
      },
      set (target, key, newValue) {
        // 數(shù)據(jù)更新
        target[key] = newValue
        // 視圖更新
        document.querySelector('#app').textContent = target[key]
      }
    })
  </script>
</body>
</html>

對(duì)深層監(jiān)控啊,屬性監(jiān)控啊克饶,遍歷啊都不需要在Vue3進(jìn)行操作了酝蜒,通過(guò)Proxy代理可以輕松解決,但是由于ES6的Proxy方法兼容性不是那么的好矾湃,所以市面上Vue3的普及度并不是太高亡脑,一切走向都需要根據(jù)市場(chǎng)來(lái)確定

相關(guān)設(shè)計(jì)模式

設(shè)計(jì)模式:針對(duì)軟件設(shè)計(jì)中普遍存在的各種問(wèn)題所提出的解決方案

觀察者模式

指的是在對(duì)象間定義一個(gè)一對(duì)多(被觀察者與多個(gè)觀察者)的關(guān)聯(lián),當(dāng)一個(gè)對(duì)象改變了狀態(tài)邀跃,所有其他相關(guān)的對(duì)象會(huì)被通知并且自動(dòng)刷新

就像是超市有一堆顧客霉咨,超市出了促銷活動(dòng),會(huì)通知顧客(觀察者)拍屑,又因?yàn)楫?dāng)前是否想要購(gòu)物途戒,進(jìn)行不同的選擇行動(dòng)

  • 核心概念:
    • 觀察者Observer
    • 被觀察者(觀察目標(biāo))Subject

      設(shè)計(jì)的核心點(diǎn)就是設(shè)置一個(gè)被觀察者,設(shè)置一個(gè)或者多個(gè)的觀察者丽涩,在被觀察者中設(shè)置一個(gè)遍歷進(jìn)行操作
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 被觀察者(觀察目標(biāo))
    // 1.需要能夠添加觀察者
    // 2.通知所有觀察者的功能
    class Subject {
      constructor () {
        // 存儲(chǔ)所有的觀察者
        this.observers = []
      }
      // 添加觀察者功能
      addObserver (observer) {
        // 檢測(cè)傳入的參數(shù)是否為觀察者實(shí)例
        if (observer && observer.update) {
          this.observers.push(observer)
        }
      }
      // 通知所有的觀察者
      notify () {
        // 調(diào)用觀察者列表中的每個(gè)觀察者的更新方法
        this.observers.forEach(observer => {
          observer.update()
        })
      }
    }
    // 觀察者
    // 1.被觀察者發(fā)生狀態(tài)變化時(shí)棺滞,做一些對(duì)應(yīng)的操作“更新”
    class Observer {
      update () {
        console.log('事件發(fā)生了,進(jìn)行一個(gè)相應(yīng)的處理...')
      }
    }

    // 功能測(cè)試
    const subject = new Subject()
    const ob1 = new Observer()
    const ob2 = new Observer()

    // 將觀察者添加給要觀察的觀察目標(biāo)
    subject.addObserver(ob1)
    subject.addObserver(ob2)

    // 通知觀察者進(jìn)行操作(某些具體的場(chǎng)景下)
    subject.notify()
  </script>
</body>
</html>

通過(guò)觀察者模式為不同的數(shù)據(jù)設(shè)置不同的觀察者,監(jiān)視被觀察者的情況矢渊,通過(guò)特定的方法進(jìn)行更新操作等等

發(fā)布-訂閱模式

可以認(rèn)為是為觀察者模式的解耦的進(jìn)階版本继准,特點(diǎn)是:

  • 在發(fā)布者和訂閱者之間添加一個(gè)消息中心,所有的消息均通過(guò)消息中心管理矮男,而發(fā)布者與訂閱者不會(huì)直接聯(lián)系移必,實(shí)現(xiàn)了兩張的解耦

核心概念:

  • 消息中心Dep
  • 訂閱者Subscriber
  • 發(fā)布者Publisher


<body>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
  <script>
    // 創(chuàng)建了一個(gè)Vue實(shí)例(消息中心)
    const eventBus = new Vue()

    // 注冊(cè)事件(設(shè)置訂閱者)
    eventBus.$on('dataChange', () => {
      console.log('事件處理功能1')
    })

    eventBus.$on('dataChange', () => {
      console.log('事件處理功能2')
    })

    // 觸發(fā)事件(設(shè)置發(fā)布者)
    eventBus.$emit('dataChange')
  </script>
</body>

設(shè)計(jì)模式小結(jié)

  • 觀察者模式是由觀察者和觀察目標(biāo)組成的,適合組件內(nèi)部操作(功能簡(jiǎn)單就可以)
    • 特性:特殊事件發(fā)生后毡鉴,觀察目標(biāo)統(tǒng)一通知所有的觀察者
  • 發(fā)布/訂閱模式由發(fā)布者與訂閱者以及消息中心組成崔泵,更加適合消息類型復(fù)雜的情況
    • 特性:特殊事件發(fā)生,消息中心接到發(fā)布指令后猪瞬,會(huì)根據(jù)事件類型給對(duì)應(yīng)的訂閱者發(fā)送信息

響應(yīng)式原理模擬

整體分析

要模擬Vue實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)憎瘸,首先我們需要觀察一下Vue實(shí)例的結(jié)構(gòu),分析要實(shí)現(xiàn)哪些屬性和功能


  • Vue:
    • 目標(biāo):將data數(shù)據(jù)注入到Vue實(shí)例陈瘦,便于方法內(nèi)操作
  • Observer(發(fā)布者)
    • 目標(biāo):數(shù)據(jù)劫持幌甘,監(jiān)聽(tīng)數(shù)據(jù)變化,并在變化時(shí)通知Dep
  • Dep(消息中心)
    • 目標(biāo):存儲(chǔ)訂閱者以及管理消息的發(fā)送
  • Watcher(訂閱者)
    • 目標(biāo):當(dāng)訂閱數(shù)據(jù)變化,進(jìn)行視圖更新
  • Compiler
    • 目標(biāo):解析模板中的指令與插值表達(dá)式锅风,并替換成相應(yīng)的數(shù)據(jù)

Vue類

  • 功能:
    • 接受配置信息
    • 將data的屬性轉(zhuǎn)換為Getter酥诽、setter,并且注入到Vue實(shí)例中
    • *監(jiān)聽(tīng)data中所有屬性的變化皱埠,設(shè)置成響應(yīng)式數(shù)據(jù)
    • *調(diào)用解析功能(解析模板內(nèi)的插值表達(dá)式肮帐,指令等等)


      1.存儲(chǔ)配置選項(xiàng),2.掛載元素边器,3.設(shè)置數(shù)據(jù)屬性训枢,最后通過(guò)proxyData將data屬性都設(shè)置到vue實(shí)例

      n _proxyData (target, data) {
      Object.keys(data).forEach(key => {
      Object.defineProperty(target, key,{
      enumerable: true,
      configurable: true,
      get () {
      return data[key]
      },
      set (newValue) {
      data[key] = newValue
      }
      })
      })
      }

Observer類

  • 功能:
  • 通過(guò)數(shù)據(jù)劫持方式監(jiān)視data中的屬性變化,變化時(shí)通知消息中心Dep
  • 需要考慮data的屬性也可能為對(duì)象饰抒,也要轉(zhuǎn)換成響應(yīng)式數(shù)據(jù)


Dep類

  • Dep是dependency的簡(jiǎn)寫肮砾,含義是“依賴”诀黍,指的是Dep用于收集與管理訂閱者與發(fā)布者之間的依賴關(guān)系
  • 功能:
    • *為每個(gè)數(shù)據(jù)收集對(duì)應(yīng)的依賴袋坑,存儲(chǔ)依賴
    • 添加并存儲(chǔ)訂閱者
    • 數(shù)據(jù)變化時(shí),通知所有的觀察者


Watcher 類

  • 功能:
    • 實(shí)例化Watch時(shí)眯勾,往dep對(duì)象中添加自己
    • 當(dāng)數(shù)據(jù)變化觸發(fā)dep枣宫,dep通知所有對(duì)應(yīng)的Watcher實(shí)例更新視圖


Complier類

  • 功能:
    • 進(jìn)行編譯模板,并解析內(nèi)部指令與插值表達(dá)式
    • 進(jìn)行頁(yè)面的首次渲染
    • 數(shù)據(jù)變化后吃环,重新渲染視圖


功能回顧與總結(jié)

  • Vue類
    • 把data的屬性注入到Vue實(shí)例
    • 調(diào)用Observer實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式處理
    • 調(diào)用Compiler編譯模板
  • Observer
    • 將data的屬性轉(zhuǎn)換為Getter/setter
    • 為Dep添加訂閱者Watcher
    • 數(shù)據(jù)變化發(fā)送時(shí)通知Dep
  • Dep
    • 收集依賴也颤,添加訂閱者(Watcher)
    • 通知訂閱者
  • Watcher
    • 編譯模板時(shí)創(chuàng)建訂閱者,訂閱數(shù)據(jù)變化
    • 接到Dep通知時(shí)郁轻,調(diào)用Compiler中的模板功能更新視圖
  • Compiler
    • 編譯模板翅娶,解析指令與插值表達(dá)式
    • 負(fù)責(zé)頁(yè)面首次渲染與數(shù)據(jù)變化后重新渲染


      功能總結(jié)圖
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市好唯,隨后出現(xiàn)的幾起案子竭沫,更是在濱河造成了極大的恐慌,老刑警劉巖骑篙,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜕提,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡靶端,警方通過(guò)查閱死者的電腦和手機(jī)谎势,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)杨名,“玉大人脏榆,你說(shuō)我怎么就攤上這事√ǖ” “怎么了须喂?”我有些...
    開(kāi)封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我镊折,道長(zhǎng)胯府,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任恨胚,我火速辦了婚禮骂因,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赃泡。我一直安慰自己寒波,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布升熊。 她就那樣靜靜地躺著俄烁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪级野。 梳的紋絲不亂的頭發(fā)上页屠,一...
    開(kāi)封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音蓖柔,去河邊找鬼辰企。 笑死,一個(gè)胖子當(dāng)著我的面吹牛况鸣,可吹牛的內(nèi)容都是我干的牢贸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼镐捧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼潜索!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起懂酱,我...
    開(kāi)封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤竹习,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后玩焰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體由驹,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年昔园,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔓榄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡默刚,死狀恐怖甥郑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荤西,我是刑警寧澤澜搅,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布伍俘,位于F島的核電站,受9級(jí)特大地震影響勉躺,放射性物質(zhì)發(fā)生泄漏癌瘾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一饵溅、第九天 我趴在偏房一處隱蔽的房頂上張望妨退。 院中可真熱鬧,春花似錦蜕企、人聲如沸咬荷。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幸乒。三九已至,卻和暖如春唇牧,著一層夾襖步出監(jiān)牢的瞬間罕扎,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工奋构, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壳影,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓弥臼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親根灯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子径缅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友烙肺。感恩相遇纳猪!感恩不離不棄。 中午開(kāi)了第一次的黨會(huì)桃笙,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,562評(píng)論 0 11
  • 彩排完氏堤,天已黑
    劉凱書法閱讀 4,209評(píng)論 1 3
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來(lái)的情緒搏明。表情可以傳達(dá)很多信息鼠锈。高興了當(dāng)然就笑了,難過(guò)就哭了星著。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,913評(píng)論 2 7