}
frag.appendChild(child);
}
//将文档碎片添加至对应node中,最后为id为app的元素下
node.appendChild(frag);
}
//初始化绑定数据
function compile(node,vm){
//node节点为元素节点时
if(node.nodeType === 1){
var attr = node.attributes;
//遍历当前节点的所有属性
for(var i=0;i<attr.length;i++){
if(attr[i].nodeName === 'v-model'){
//属性名
var name = attr[i].nodeValue;
//将data下对应属性名的值赋值给当前节点值
//这里因为node是input标签所以值为node.value
node.value = vm.data[name];
//最后标签中的v-model属性也可以功成身退了,删除它
node.removeAttribute(attr[i].nodeName);
}
}
}
//node节点为text文本节点#text时
if(node.nodeType === 3){
var reg = /{{(.*)}}/;
if(reg.test(node.nodeValue.trim())){
//将正则匹配到的{{}}中的字符串赋值给name
var name = RegExp.$1;
//利用name对应赋值相应的节点值
node.nodeValue = vm.data[name];
}
}
}
//MVVM构造函数,这里我就写成Vue了
function Vue(options){
this.id = options.el;
this.data = options.data;
//将根节点与实例化后的对象作为参数传入
nodeToFragment(document.getElementById(this.id),this);
}
//实例化
var vm = new Vue({
el:'app',
data:{
msg:'hello,two-ways-binding',
test:'test key'
}
})
上述就是简单的单向绑定了,整个逻辑实际上非常简单,我再来跟大家说明一下
1、为了令model层的数据可以绑定到view层的dom上,所以我们想了一个办法来替换dom中的一些元素值,而明显一个个替换时不可取的,因为大量的dom操作会降低程序的运行效率,你想想,每次dom操作可都是一次对dom整体的遍历过程~,所以我们觉得采用文档碎片的形式,将dom一次全部劫持,在内存中执行全部数据绑定操作,最后只进行一次dom操作,即添加子节点来解决这个频繁操作dom的问题,你也可以理解为中间的一层存在于内存中的虚拟dom;
2、那么既然如此,我们就要首先劫持所有dom节点,这里我们利用nodeToFragment函数来劫持;
3、在每次劫持对应dom节点的过程中,我们也会相对应的实现对该dom元素的数据绑定,以求在最后直接添加到为根节点的子元素即可,这个过程我们就在nodeToFragment函数中插入了compile函数来初始化绑定,并且添加递归函数实现所有子元素的初始绑定;
4、在compile函数中我们添加的数据又从何而来呢?对,正是因为这点,所以我们建立MVVM的构造函数Vue来实现数据支持,并实现在实例化时就执行nodeToFragment同时重构dom和实现初始化绑定compile;
5、好了,单向绑定就是这么简单,4个函数即可Vue => nodeToFragment => compile => isChild。










