vue双向绑定的简单实现

2020-06-16 05:44:46易采站长站整理

完成图如下

好了,再回过来看看整体的流程图,我们已经实现了这一块了

接下来,休息下,大家准备开始流程图后面的双向绑定,ok,还是按照单向绑定的顺序,先跟大家讲明实现逻辑;

1、创建数据监听者observer去监听view层数据的变化;(利用Object.defineProperty劫持所有要用到的数据)

2、当view层数据变化后,通过通知者Dep通知订阅者去实现数据的更新;(通知后,遍历所有用到数据的订阅者更新数据)

3、订阅者watcher接收到view层数据变更后,重新对变化的数据进行赋值,改变model层,从而改变所有view层用到过该数据的地方。(更新数据,并改变view层所有用到该数据的节点值)

上面是实现逻辑,下面将通过具体代码告诉大家每一步的做法,由于双向绑定中订阅者会涉及初始化绑定的过程,所以代码量较多,我会在大更改处用——为大家框出来


//判断每个dom节点是否拥有子节点,若有则返回该节点
function isChild(node){
if(node.childNodes.length ===0){
return false;
}
else{
return node;
}
}

//利用文档碎片劫持dom结构及数据,进而进行dom的重构
function nodeToFragment(node,vm){
var frag = document.createDocumentFragment();
var child;
while(child = node.firstChild){
//一级dom节点数据绑定
compile(child,vm);
//判断每个一级dom节点是否有二级节点,若有则递归处理文档碎片
if(isChild(child)){
nodeToFragment(isChild(child),vm);
}
frag.appendChild(child);
}
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;
//特殊处理input标签
//------------------------
if(node.nodeName === 'INPUT'){
node.addEventListener('keyup',function(e){
vm[name] = e.target.value;
})
}
//由于数据已经由data劫持至vm下,所以直接赋值vm[name]即可触发getter访问器
node.value = vm[name];
//-------------------------
node.removeAttribute(attr[i].nodeName);
}
}
}

//node节点为text文本节点时
if(node.nodeType === 3){
var reg = /{{(.*)}}/;
if(reg.test(node.nodeValue.trim())){
var name = RegExp.$1;
//node.nodeValue = vm[name];
//----------------------