vue双向绑定

单向绑定,首先是m-->v,比如对下面html模板:

    <div id="test">
      <p>{{msg}}</p>
      <p>{{msg}}</p>
      <p>{{msg}}</p>
      <p>{{what}}</p>
      <p>{{hey}}</p>
    </div>
// 绑定标示字段,用于匹配
var bindingMark = 'data-element-binding'

function Element (id, initData) {
    var self     = this,
        el       = self.el = document.getElementById(id)
        bindings = {} // the internal copy
        data     = self.data = {} // the external interface

        // 扫描dom结构,将el中的{{xx}}绑定都替换掉,代换成span
        function markToken (match, variable) {
            bindings[variable] = {}
            return ''
        }
        content  = el.innerHTML.replace(/\{\{(.*)\}\}/g, markToken)
        el.innerHTML = content

        // 建立关联,当变量改变时改变dom
        // 初始化数据
        if (initData) {
            for (var variable in initData) {
                data[variable] = initData[variable]
            }
        }

        // 绑定函数
        function bind (variable) {
            // 根据之前的扫描去掉属性,并获取到需要绑定的span节点
            bindings[variable].els = el.querySelectorAll('[' + bindingMark + '="' + variable + '"]')
            ;[].forEach.call(bindings[variable].els, function (e) {
                e.removeAttribute(bindingMark)
            })

            // 核心函数,
            Object.defineProperty(data, variable, {
                set: function (newVal) {
                    [].forEach.call(bindings[variable].els, function (e) {
                        // 改变变量到dom,并赋值到缓存体系
                        bindings[variable].value = e.textContent = newVal
                    })
                },

                get: function () {
                    return bindings[variable].value
                }
            })
        }

        //  变量绑定入口
        for (var variable in bindings) {
            bind(variable)
        }


}
// 方式
var app = new Element('test', {
    msg: 'hello'
})

双向绑定,view交互,input,select等: 以input(v-model)为例:


// 绑定事件
this.on('change', this.rawListener)
if (!lazy) {
    this.on('input', this.listener)
}

// 更新变量
    this.listener = this.rawListener = function () {
      if (composing || !self._bound) {
        return
      }
      var val = number || isRange
        ? toNumber(el.value)
        : el.value
      // 对事件进行响应,更新变量
      self.set(val)
      // 刷新dom
      nextTick(function () {
        if (self._bound && !self.focused) {
          self.update(self._watcher.value)
        }
      })
    }

其余大同小异,具体参看vue/src/directives/public/model

Table of Contents