<!DOCTYPE html>
<html>
<head>
<title>vue-mue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text"> {{text}} <br/>
<input type="text" v-model="name"> {{name}}
</div>
<script>
/*
订阅者
*/
class Watcher{
constructor(vm, node, name) {
Dep.target = this;
this.vm = vm;
this.node = node;
this.name = name;
this.update();
Dep.target = null;
}
update(){
this.get();
this.node.nodeValue = this.value;
}
get(){
// get value
this.value = this.vm[this.name];
}
}
/*
发布者仓库
*/
class Dep{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub);
}
notify(){
this.subs.forEach(function(sub){
sub.update();
})
}
}
/*
构造Mue
*/
class Mue{
constructor(options){
this.data = options.data;
var data = this.data;
var id = options.el;
var el = document.getElementById(id);
observe(data, this); //model 加工入口
var dom = nodeToFragment(el, this);
el.appendChild(dom);
}
}
function observe(data, vm){ //data: {text: 'hello'}
Object.keys(data).forEach(function(key){
defineReactive(vm, key, data[key]);
})
}
function defineReactive(vm, key, val){
var dep = new Dep();
Object.defineProperty(vm, key, {
get: function(){
console.log(`获取数据${val}`);
if(Dep.target){
dep.addSub(Dep.target);
}
//set init value from data
return val;
},
set: function(newValue){
if(newValue === val) return;
val = newValue;
console.log(`数据更新${val}`);
dep.notify();
}
})
}
/*
node 容器dom节点 这里指id为app的div标签节点
vm 实例化Mue对象
*/
function nodeToFragment(node, vm){
var frag = document.createDocumentFragment();
var child;
while(child = node.firstChild){
compile(child, vm);
frag.append(child);
}
return frag;
}
/*
node 遍历后的节点(元素节点、文本节点等)
vm 实例化Mue对象
*/
function compile(node, vm){
var reg = /\{\{(.*)\}\}/;
//处理元素节点
if(node.nodeType === 1){
if(node.hasAttribute('v-model')){
var name = node.getAttribute('v-model');
node.addEventListener('input', function(e){
//set value
vm[name] = e.target.value;
})
}
//get value
node.value = vm[name];
node.removeAttribute('v-model');
}
//处理文本节点
if(node.nodeType === 3){
if(reg.test(node.nodeValue)){
var name = RegExp.$1;
name = name.trim();
//get value
node.nodeValue = vm[name];
}
new Watcher(vm, node, name); //订阅入口
}
}
//实例化Mue对象
var app = new Mue({
el: 'app',
data: {
text: 'Well',
name: 'john'
}
})
</script>
</body>
</html>