<!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>