Detailed explanation of Vue's two-way binding principle

Vue's two-way binding principle

Vue adopts the method of data hijacking combined with the publisher-subscriber mode, and hijacks the setter and getter properties of each property through Object.defineProperty(). When the data changes, the subscriber is notified, the update callback function is triggered, and the view is re-rendered

key element

Observer implements monitoring of various properties of vue

function observer(obj, vm){
    
    
      Object.keys(obj).forEach(function(key){
    
    
          defineReactive(vm, key, obj[key])
  })
}
// Object.defineProperty改写各个属性
function defineReactive( obj, key, val ) {
    
    
    // 每个属性建立个依赖收集对象,get中收集依赖,set中触发依赖,调用更新函数 
    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
            // 触发依赖
            dep.notify()
            val = newVal
      }
  })
}
-Dep implementation
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 implements the parser for each instruction template of vue, generates AST abstract syntax tree, compiles it into Virtual Dom, and renders the view

function compiler(node, vm){
    
    
    var reg = /\{
    
    \{
    
    (.*)\}\}/;
    // 节点类型为元素
    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属性赋值,触发修改属性的setter
                    vm[_value] = e.target.value
                })
                node.value = vm[_value] // 将data的值赋值给node
                node.removeAttribute('v-model')
            }
        }
        new Watcher(vm,node,_value,'input')
    }
    // 节点类型为text
    if(node.nodeType ===3){
    
    
       if(reg.test(node.nodeValue)){
    
    
           var name = RegExp.$1; 
            name = name.trim()
            new Watcher(vm,node,name,'input')
       }
    }
}

Watcher connects observer and compiler, accepts the notification of each attribute change, binds the update function, and updates the view

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() // 绑定更新函数
    Dep.target = null //绑定完后注销 标志
}
Watcher.prototype = {
    
    
    get: function(){
    
    
        this.value = this.vm[this.name] //触发observer中的getter监听
  },
   update: function(){
    
    
      this.get()
      if(this.nodeType == 'text'){
    
    
        this.node.nodeValue = this.value
      }   
      if(this.nodeType == 'input') {
    
    
          this.node.value = this.value
    }
  }
}

fully realized

function Vue(options){
    
    
    this.date = options.data
    var data = this.data
    observer(data, this) // 监测
    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"
  }
})

おすすめ

転載: blog.csdn.net/weixin_45449504/article/details/102824201