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