淺析vue數據綁定


前言:最近團隊需要做一個分享,腳進腦子,不知如何分享。最后想着之前一直想研究一下 vue 源碼,今天剛好 “借此機會” 研究一下。

網上研究vue數據綁定的文章已經非常多了,但是自己寫一遍,敲一遍demo和看別人的文章是完全不同的,so……搬運工來了

 

目前數據綁定主要有以下三種實現方式:

1.   臟值檢查(angular.js)    輪詢檢測數據變化
DOM事件,譬如用戶輸入文本,點擊按鈕等。( ng-click )
  • XHR響應事件 ( $http )
  • 瀏覽器Location變更事件 ( $location )
  • Timer事件( $timeout , $interval )
  • 執行 $digest() 或 $apply()
2、Object.defineProperty劫持對象的get、set,從而實現對數據的監控。 (vue)
3、發布/訂閱者模式實現數據與視圖的自動同步
 
Object.defineProperty的優點
  • “臟值檢測”——數據發生變更后,對於所有的數據和視圖的綁定關系進行一次檢測,識別是否有數據發生了改變,有變化進行處理,可能進一步引發其他數據的改變,所以這個過程可能會循環幾次,一直到不再有數據變化發生后,將變更的數據發送到視圖,更新頁面展現 
  • Object.defineProperty() 監控對數據的操作,可以自動觸發數據同步。並且,由於是在不同的數據上觸發同步,可以精確的將變更發送給綁定的視圖,而不是對所有的數據都執行一次檢測。
 
Object.defineProperty的用法
var a = {};

Object.defineProperty(a, "b", {
    
    set: function (newValue) {
        
        console.log("我被賦值了!" + newValue);
    
     },
    
    get: function () {
        
        console.log("我被取值了!");
        
        return 2   
    }
})

a.b = 3; //我被賦值了!
console.log(a.b);   //我被取值了!       //打印 2            
由上面的例子看出,Object.defineProperty  傳人3個參數
第一個: a對象
第二個: a對象里面的b屬性
第三個: 屬性比較多,列舉有用的 value,set,get,configurable
 
 
數據綁定原理:
1、實現一個數據監聽器Observer,對數據對象的所有屬性進行監聽,如有變動則拿到最新值並通知 dep數組
2、實現一個指令解析器Compile,對每個元素節點的指令進行掃描和解析,根據指令模板替換數據
3、實現一個dep數組 ,能夠訂閱並收到每個屬性變動的通知,執行指令綁定的相應回調函數,更新視圖
 
 
1. 實現observer
var data = {name: 'beidan'};

observe(data);

data.name = 'test'; // 監聽到值變化了  beidan  變成  test

function observe(data) {
    
     if (!data || typeof data !== 'object') {
        
       return;
    
     }
    
     // 取出所有屬性遍歷    
    Object.keys(data).forEach(function(key) {
    
         defineReactive(data, key, data[key]);

  });
}
function defineReactive(data, key, val) {


    Object.defineProperty(data, key, {

        enumerable: true, // 可枚舉        
                configurable: false, // 不能再define        
                get: function() {
            
                    return val;
        
                },
        
                set: function(newVal) {
            
                    console.log('監聽到值變化了 ', val, ' 變成 ', newVal);

                    val = newVal;
        
                }
    
        });
}                        

2. 維護一個數組

function Dep() {
   
     this.subs = [];
}

Dep.prototype = {
    
    addSub: function (sub) {
        
       this.subs.push(sub);
    
    },
   
     notify: function (val) {
       
         this.subs.forEach(function (sub) {
            
            sub.update(val)
        
        });
    
}
};

function defineReactive(data, key, val) {
   Object.defineProperty(data, key, {
     ……
      set: function(newVal) {
           if (val === newVal) return;
            console.log('監聽到值變化了 ', val, ' 變成 ', newVal);
            val = newVal;
            dep.notify(val); // 通知所有訂閱者     
      } 
    });
}                

3. compile

bindText: function () {
    
    var textDOMs = this.el.querySelectorAll('[v-text]'),
bindText,_context = this;

   
    for (var i = 0; i < textDOMs.length; i++) {
         
       bindText = textDOMs[i].getAttribute('v-text');
  
       textDOMs[i].innerHTML = this.data[bindText];

        
       var val = textDOMs[i]

        
       var up = function (text) {
           
         val.innerText = text
        
       }

       _context.dep.addSub({
            
            value: textDOMs[i],
            
            update: up
       
       });
   
 }
},                    

 

 
 
最后,附上源碼 github   https://github.com/beidan/vue_bind
 
 
參考鏈接:
http://www.cnblogs.com/LuckyWinty/p/6102913.html
http://www.cnblogs.com/kidney/p/6052935.html?utm_source=gold_browser_extension
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM