理解VUE双向数据绑定原理和实现
程序员文章站
2022-07-12 21:54:06
...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model='text'>
{{text}}
</div>
<script>
function nodeToFragment(node,vm) {
let fragment = document.createDocumentFragment();
let child;
while (child = node.firstChild) {
compile(child,vm)
fragment.appendChild(child);
}
return fragment;
}
// let dom = nodeToFragment(document.getElementById('app'));
function compile(node, vm) {
let reg = /\{\{(.*)\}\}/; //用来匹配{{xxx}}中的xxx
//如果是元素节点
if(node.nodeType === 1){
let attr = node.attributes;
let attrLen = attr.length;
//解析元素节点的所有属性
for(let i = 0; i < attrLen; i++){
if(attr[i].nodeName == 'v-model'){
let name = attr[i].nodeValue;//看看是与哪一个数据有关
node.addEventListener('input',function(e){
vm[name] = e.target.value;
})
node.value = vm[name];//将data的值赋给该node
node.removeAttribute('v-model');
}
}
}
//如果是文本节点
if(node.nodeType === 3){
if(reg.test(node.nodeValue)){
let name = RegExp.$1;//匹配到获取的字符串
name = name.trim();
// node.nodeValue = vm[name];
new Watcher(vm, node, name)
}
}
}
//创建Vue的实例化函数
function Vue(options){
this.data = options.data;
let data = this.data;
observe(data,this);
let id = options.el;
let dom = nodeToFragment(document.getElementById(id),this);
//处理完所有dom节点后,重新将内容添加回去;
document.getElementById(id).appendChild(dom);
};
//响应式监听属性的函数
function defineReactive(obj,key,val){
let dep = new Dep();
Object.defineProperty(obj,key,{
get:function(){
// console.log(Dep.target)
if(Dep.target){
dep.addSub(Dep.target);
}
return val;
},
set:function(newVal){
if(newVal === val){
return;
}
val = newVal;
//console.log('新值:'+val);
//一旦更新立马通知
dep.notify();
}
})
};
//实现一个观察者,对于一个实例 每一个属性值都进行观察。
function observe(obj,vm){
for(let key of Object.keys(obj)){
defineReactive(vm,key,obj[key])
}
}
//Watcher构造函数
function Watcher(vm,node,name){
Dep.target = this;
this.vm = vm;
this.node = node;
this.name = name;
this.update();
Dep.target = null;
}
Watcher.prototype = {
update(){
this.get();
console.log(this.value)
this.node.nodeValue = this.value; //注意。这是更改节点内容的关键
},
get(){
this.value = this.vm[this.name];
}
}
//dep构造函数
function Dep(){
this.subs = [];
}
Dep.prototype = {
addSub(sub){
this.subs.push(sub);
},
notify(){
this.subs.forEach(sub=>{
// console.log(sub)
sub.update();
})
}
}
let vm = new Vue({
el:'app',
data:{
text:''
}
})
</script>
</body>
</html>
上一篇: HTTPS加密过程和TLS证书验证