美文网首页
vue源码解读 -- 双向绑定

vue源码解读 -- 双向绑定

作者: 狐尼克朱迪 | 来源:发表于2017-03-01 15:01 被阅读0次

    双向绑定是MVVM框架中一个基本也是很诱人的功能,它能够让我们减少dom操作,进而极大减少我们的代码量。我们可以通过指令把一个input的value值和Model中字段关联,而不再需要dom取出此节点,然后获取节点的value。
    本文以v-model指令为例,分析vue中双向绑定的基本实现。在vue源码解读 -- 整体架构一文中,我们已经分析vue的基本运行机制,本文就不再对这些方面的内容进行展开。

    一个例子

    如下面的例子,当input框中的值改变时,p标签中的值也跟着变化

    <div id="app">
      <input type="text" v-model="a" />
      <p>{{a}}</p>
    </div>
    
    <script>
      var model = new Vue({
        el: '#app',
        data: {
          a: 1
        }
      });
    </script>```
    
    #####基本原理
    DOM结构进行compile后生成linker函数,linker函数执行后返回一个unlinker函数供后续节点移除时调用(接触事件绑定、指令监听等)。linker函数执行会生成DOM中调用到的指令列表,指令经过优先级排序,然后执行bind操作:
    

    dirs[i]._bind()

    一个Directive对象的构成如下所示。el指DOM节点;expression表示指令中的表达式;name是基础指令的名称,通过它找到对应的方法;priority表示优先级。
    
    ![Paste_Image.png](https://img.haomeiwen.com/i1975863/c8b91641484af0b4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    Directive的_bind函数主要做了两件事情:调用基本指令的bind和生成watcher对象。 前者是指令自身逻辑的确定;后者是绑定data的view的桥梁,当数据变化时会通过update实现指令更新。
    
    #####指令的bind和update
    
    ######1. v-text
    
    {{}}和v-text都会调用text指令,下面是其bind和update方法:bind方法进行一些预处理工作,update则自己进行view的更新。
    

    bind () {
    // 节点为element时 通过textContent更新
    // 节点为text时,通过data更新
    this.attr = this.el.nodeType === 3
    ? 'data'
    : 'textContent'
    },
    update (value) {
    this.el[this.attr] = _toString(value)
    }

    
    ######2. v-model
    例子中的v-model,其指令的bind和update方法如下:
    

    bind () {
    ...
    if (tag === 'INPUT') {
    handler = handlers[el.type] || handlers.text
    ...
    handler.bind.call(this)
    this.update = handler.update
    this._unbind = handler.unbind
    },

    handler的bind和update方法:
    

    bind () {
    var self = this
    // Now attach the main listener
    this.listener = function () {
    var val = number || isRange ? toNumber(el.value) : el.value
    self.set(val)
    nextTick(function () {
    if (self._bound && !self.focused) {
    self.update(self._watcher.value)
    }
    })
    }
    ...
    this.on('change', this.listener)
    if (!lazy) {
    this.on('input', this.listener)
    }
    ...
    },
    update (value) {
    this.el.value = _toString(value)
    },

    v-model指令中的bind对input的change和input事件进行了监听,当input中值改变是,会调用Directive的set方法,然后一步调用update方法。set方法的逻辑如下:
    

    Directive.prototype.set = function (value) {
    if (this.twoWay) {
    this._withLock(function () {
    this._watcher.set(value)
    })
    }
    ...
    }

    Watcher.prototype.set = function (value) {
    var scope = this.scope || this.vm
    // 如果有过滤器 执行过滤器逻辑
    if (this.filters) {
    value = scope._applyFilters(
    value, this.value, this.filters, true)
    }
    try {
    // 调用setter更新vm中的值 同事执行依赖的notify
    this.setter.call(scope, scope, value)
    }
    ...
    }

    
    上述就是vue实现双向绑定的一个基本思路,其根本还是通过DOM的事件体系进行监听。当数据变化时,首先改变vm中的值,然后调用依赖的notify方法实现其他View的同步更新。

    相关文章

      网友评论

          本文标题:vue源码解读 -- 双向绑定

          本文链接:https://www.haomeiwen.com/subject/uwhzsttx.html