首先我们要知道Vue双向绑定的几个概念
1.comple(解析器):主要是用来解析你的节点、子节点、属性(w-on: ,w-html,w-model)
2.observe(观察者):主要是来对data中的属性进行监听( Object.defineProperty)
3.watcher(订阅者):主要是用来接受数据变化,进而实现视图更新
好了直接撸代码吧
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./index.js"></script>
</head>
<body>
<div id="myApp">
<input type="button" value="按钮" w-on:click="fn">
<input type="text" style="width:400px" w-model="advice">
<div w-text="advice"></div>
<div w-html="advice"></div>
</div>
</body>
<script>
var vm = new Wang({
el: "#myApp",
data: {
advice: "<a href='javaScript:;'>加油吧少年</a>"
},
methods: {
fn() {
this.advice += "!";
}
}
})
</script>
</html>
index.js
function Wang(options){
this.$el = document.querySelector(options.el);
this.$data = options.data;
this.$methods = options.methods;
this.binding = {};
this.observer();
this.compile(this.$el);
}
Wang.prototype.observer=function(){
var value = '';
Object.keys(this.$data).forEach(key=>{
value = this.$data[key];
this.binding[key] = [];
var binding = this.binding[key];
Object.defineProperty(this.$data,key,{
get(){
return value;
},
set(v){
if(v!==value){
value = v;
binding.forEach(item=>{//这里binding是浅拷贝
item.update();
})
}
}
})
})
}
Wang.prototype.compile = function(el){
var nodes =el.children;
for(var i =0 ;i<nodes.length;i++){
var node = nodes[i];
if(node.children.length>0){
this.compile(node);
}
if(node.hasAttribute('w-on:click')){
var attrVal = node.getAttribute('w-on:click');
node.addEventListener("click",this.$methods[attrVal].bind(this.$data))
}
if(node.hasAttribute('w-html')){
var attrVal = node.getAttribute('w-html');
this.binding[attrVal].push(new Watcher(node,"innerHTML",this,attrVal))
}
if(node.hasAttribute('w-text')){
var attrVal = node.getAttribute('w-text');
this.binding[attrVal].push(new Watcher(node,"innerText",this,attrVal))
}
if(node.hasAttribute('w-model')){
var attrVal = node.getAttribute('w-model');
node.addEventListener('input',((i)=>{
this.binding[attrVal].push(new Watcher(node,"value",this,attrVal));
return ()=>{
this.$data[attrVal] = nodes[i].value;
}
})(i))
}
}
}
function Watcher(el,attr,vm,value){
this.el = el;
this.attr = attr;
this.vm = vm;
this.value = value;
this.update();
}
Watcher.prototype.update=function(){
this.el[this.attr] = this.vm.$data[this.value]
}
别急还有个简单的双向绑定让你更好的理解Object.defineProperty
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./index.js"></script>
</head>
<body>
<input type="text" id="tet">
<div id="box"></div>
</body>
<script>
var oText = document.getElementById("tet");
var oDiv = document.getElementById("box");
var name="隔壁老王"
var obj = {
name
}
Object.defineProperty(obj,"name",{
get(){
return name;
},
set(v){
oText.value = oDiv.innerHTML = v
}
})
oText.value = oDiv.innerHTML = obj.name;
oText.onkeyup=function(){
obj.name = this.value;
}
</script>
</html>
最好感谢张培跃老师的原文指导