- 双向数据绑定建立在单向数据绑定(model-view)的基础之上
- 实现流程:
- 解析v-model指令时给当前元素添加input监听
- 当input的value发生改变时,将最新的值赋给当前表达式所对应的data属性
Compile.prototype = {
compile: function (node) {
var attrs = node.attributes,
me = this;
[].slice.call(attrs).forEach(function (attr) {
var attrName = attr.name
if (me.isDrection(attrName)) {
var exp = attrName.value,
dir = attrName.slice(2);
if (me.isEventDirection(dir)) {
eventHandler(node, me.$vm, dir, exp)
} else {
compileUtil[dir] && compileUtil[dir](node, me.$vm, exp) // 解析普通指令
}
node.removeAttribute(attrName)
}
})
},
}
var compileUtil = {
// 解析v-model
model: function (node, vm, exp) {
// 实现数据的初始化显示和创建对应的watcher
this.bind(node, vm, exp, 'model')
var value = this.getVMVal(vm, exp),
me = this;
// 给节点绑定input事件监听(输入改变时)
node.addEventListener('input', function () {
var newValue = e.target.value
if (newValue === value) {
return
}
// 将最新的value保存给表达式所对应的属性
me.setVMVal(vm, exp, newValue)
val = newValue
})
},
bind: function (node, vm, exp, dir) {
var updateFn = updater[dir+'Updater']
updateFn && updateFn(node, this.getVMVal(vm, exp))
// 为表达式创建一个对应的watcher,实现节点的更新
new Watcher(vm, exp, function (value, oldValue) {//当表达式对应的一个属性值变化时回调
// 更新界面中的指定节点
updateFn && updateFn(node, value, oldValue)
})
},
updateFn: function (node, val) {
node.textContent = typeof val === 'undefined' ? '' : val
},
setVMVal: function (vm, exp, value) {
var val = vm
exp = exp.split('.')
exp.forEach(function (k, i) {
if (i < exp.length - 1) {
val = val[k]
} else {
val[k] = value
}
})
return val
},
}
var updater = {
modelUpdater: function (node, val) {
node.value = typeof val === 'undefined' ? '' : val;
},
}