Vue的雙向綁定原理及實現(xiàn)

一圖勝千言

流程圖

原理:
Vue采用數(shù)據(jù)劫持結合發(fā)布者-訂閱者模式的方法幢尚,通過Object.defineProperty()來劫持各個屬性的setter,getter屬性,在數(shù)據(jù)變動話户魏,通知訂閱者付秕,觸發(fā)更新回調函數(shù)字旭,重新渲染視圖

關鍵要素
  • observer 實現(xiàn)對vue各個屬性進行監(jiān)聽
function observer(obj, vm){
      Object.keys(obj).forEach(function(key){
          defineReactive(vm, key, obj[key])
  })
}
// Object.defineProperty改寫各個屬性
function defineReactive( obj, key, val ) {
    // 每個屬性建立個依賴收集對象,get中收集依賴,set中觸發(fā)依賴哟沫,調用更新函數(shù) 
    var dep = new Dep();
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function() {
          // 收集依賴  Dep.target標志
          Dep.target && dep.addSub(Dep.target)
          return val
        },
        set: function(newVal){
            if(newVal === val) return
            // 觸發(fā)依賴
            dep.notify()
            val = newVal
      }
  })
}

-Dep實現(xiàn)

function Dep(){
    this.subs = []
}
Dep.prototype = {
    constructor: Dep,
    addSub: function(sub){
        this.subs.push(sub)
    },
    notify: function(){
        this.subs.forEach(function(sub){
            sub.update() // 調用的Watcher的update方法
      })
    }
}
  • compiler 實現(xiàn)對vue各個指令模板的解析器,生成AST抽象語法樹锌介,編譯成Virtual Dom嗜诀,渲染視圖
// 編譯器
function compiler(node, vm){
    var reg = /\{\{(.*)\}\}/;
    // 節(jié)點類型為元素
    if(node.nodeType ===1){
        var attr = node.attributes;
        // 解析屬性
        for(var i=0; i< attr.length;i++){
                if(attr[i].nodeName == 'v-model'){
                var  _value = attr[i].nodeValue
                 node.addEventListener('input', function(e){
                    //給相應的data屬性賦值,觸發(fā)修改屬性的setter
                    vm[_value] = e.target.value
                })
                node.value = vm[_value] // 將data的值賦值給node
                node.removeAttribute('v-model')
            }
        }
        new Watcher(vm,node,_value,'input')
    }
    // 節(jié)點類型為text
    if(node.nodeType ===3){
       if(reg.test(node.nodeValue)){
           var name = RegExp.$1; 
            name = name.trim()
            new Watcher(vm,node,name,'input')
       }
    }
}
  • Watcher 連接observer和compiler,接受每個屬性變動的通知孔祸,綁定更新函數(shù)隆敢,更新視圖
function Watcher(vm,node,name, nodeType){
    Dep.target = this; // this為watcher實例
    this.name = name
    this.node = node 
    this.vm = vm
    this.nodeType = nodeType
    this.update() // 綁定更新函數(shù)
    Dep.target = null //綁定完后注銷 標志
}
Watcher.prototype = {
    get: function(){
        this.value = this.vm[this.name] //觸發(fā)observer中的getter監(jiān)聽
  },
   update: function(){
      this.get()
      if(this.nodeType == 'text'){
        this.node.nodeValue = this.value
      }   
      if(this.nodeType == 'input') {
          this.node.value = this.value
    }
  }
}

完整實現(xiàn)

function Vue(options){
    this.date = options.data
    var data = this.data
    observer(data, this) // 監(jiān)測
    var id = options.el
    var dom = nodeToFragment(document.getElmentById(id),this) //生成Virtual Dom
  // 編譯完成后,生成視圖
    document.getElementById(id).appendChild(dom)    
 }
function nodeToFragment(node, vm){
    var flag = document.createDocumentFragment()
    var child
    while(child = node.firstChild){
        compiler(cild, vm)
        flag.appendChild(child)
  }
  return flag
}

// 調用
  var vm = new Vue({
    el: "app",
    data: {
        msg: "hello word"
  }
})

參考文獻:
https://juejin.im/post/5b2f0769e51d45589f46949e
https://juejin.im/post/5b80e60de51d4557b85fc8fc

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末崔慧,一起剝皮案震驚了整個濱河市拂蝎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惶室,老刑警劉巖温自,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異皇钞,居然都是意外死亡悼泌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門夹界,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馆里,“玉大人,你說我怎么就攤上這事可柿∫舶荩” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵趾痘,是天一觀的道長慢哈。 經(jīng)常有香客問我,道長永票,這世上最難降的妖魔是什么卵贱? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮侣集,結果婚禮上键俱,老公的妹妹穿的比我還像新娘。我一直安慰自己世分,他們只是感情好编振,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著臭埋,像睡著了一般踪央。 火紅的嫁衣襯著肌膚如雪臀玄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天畅蹂,我揣著相機與錄音健无,去河邊找鬼。 笑死液斜,一個胖子當著我的面吹牛累贤,可吹牛的內容都是我干的。 我是一名探鬼主播少漆,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼臼膏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了示损?” 一聲冷哼從身側響起讶请,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屎媳,沒想到半個月后夺溢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡烛谊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年风响,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丹禀。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡状勤,死狀恐怖,靈堂內的尸體忽然破棺而出双泪,到底是詐尸還是另有隱情持搜,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布焙矛,位于F島的核電站葫盼,受9級特大地震影響,放射性物質發(fā)生泄漏村斟。R本人自食惡果不足惜贫导,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蟆盹。 院中可真熱鬧孩灯,春花似錦、人聲如沸逾滥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讥巡,卻和暖如春掀亩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尚卫。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尸红,地道東北人吱涉。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像外里,于是被迫代替她去往敵國和親怎爵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內容

  • 喜歡一個人盅蝗,以為命中注定 卻不知鳖链,一往情深有時只是誤會 人海茫茫中遇見了你 讓我怎能不珍惜,只是可惜 要等的人――...
    嶺南孤煙閱讀 423評論 0 0
  • 悄悄說:無論何時灌侣,溫和的性格都會是我們行走在人間,最好的通行證裂问。 和溫和的人打交道侧啼,總會讓人感覺像是在呼吸純凈的空...
    北早MEDIA閱讀 1,069評論 0 0