We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
<!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"> <h2>{{title}}</h2> <h1>{{name}}</h1> <input type="text" v-model="name" v-on:blur="blur"> <button v-on:click="clickMe">click me!</button> </div> <script> // 监听器 function observe(data){ if(Object.prototype.toString.call(data)!=='[object Object]'){ return; } Object.keys(data).forEach(key=>{ defineReactive(data,key,data[key]) }) } function defineReactive(data,key,value){ observe(value); var dep = new Dep(); Object.defineProperty(data,key,{ enumerable: true, configurable: true, get: function(){ if(Dep.target){ dep.addSub(Dep.target); // 添加一个订阅者 } return value; }, set: function(newVal){ if(newVal === value){ return; } console.log('value changed,\nthe old value is '+ value + ',\nthe new value is ' + newVal); value = newVal; dep.notify(); // 如果数据变化,通知所有订阅者 } }) } // 消息订阅器 function Dep(){ this.subs = []; } Dep.prototype = { constructor: Dep, addSub: function(sub){ this.subs.push(sub); }, notify: function(){ this.subs.map(sub=>{ sub.update(); }) } } // 订阅器 function Watcher(vm,exp,cb){ this.vm = vm; this.exp = exp; this.cb = cb; this.value = this.get(); } Watcher.prototype = { constructor: Watcher, get: function(){ Dep.target = this; var value = this.vm.data[this.exp] // 强制执行监听器里的get函数 Dep.target = null; return value; }, update: function(){ this.run(); }, run: function(){ var value = this.vm.data[this.exp]; var oldVal = this.value; if(value!==oldVal){ this.value = value; this.cb.call(this.vm,value,oldVal); } } } // 解析器 /* 将需要解析的dom节点存入fragment片段 */ function Compile(el,vm){ this.vm = vm; console.log(this.vm); this.el = document.querySelector(el); this.fragment = null; this.init(); } Compile.prototype = { constructor: Compile, init: function(){ if(!this.el){ return; } this.fragment = this.nodeToFragment(this.el); this.compileElement(this.fragment); this.el.appendChild(this.fragment); }, nodeToFragment: function(el){ var fragment = document.createDocumentFragment(); var child = el.firstChild; while(child){ fragment.appendChild(child); child = el.firstChild; } return fragment; }, compileElement: function(el){ var childNodes = el.childNodes; var self = this; [].slice.call(childNodes).forEach(child=>{ var text = child.textContent; var reg = /\{\{(.*)\}\}/; if(self.isElementNode(child)){ self.compileDirective(child); } if(self.isTextNode(child) && reg.test(text)){ self.compileText(child, reg.exec(text)[1]); } if(child.childNodes && child.childNodes.length){ self.compileElement(child); } }) }, compileDirective: function(node){ var attrs = node.attributes; var self = this; [].slice.call(attrs).forEach(attr=>{ var name = attr.name; if(self.isDirective(name)){ var exp = attr.value; var dir = name.substring(2); if(self.isEventDirentive(dir)){ // 事件指令 console.log('event') self.compileEvent(node,self.vm,exp,dir) }else{ // v-model指令 self.compileModel(node,self.vm,exp,dir) } node.removeAttribute(name); } }) }, compileText: function(node,exp){ var self = this; var initText = this.vm[exp]; this.updateText(node,initText); new Watcher(this.vm,exp,function(value){ self.updateText(node,value) }) }, compileEvent: function(node,vm,exp,dir){ var eventName = dir.split(':')[1]; var cb = this.vm.methods && this.vm.methods[exp]; if(eventName && cb){ console.log('bind event') node.addEventListener(eventName,cb.bind(vm),false); } }, compileModel: function(node,vm,exp,dir){ var self = this; var val = this.vm[exp]; this.modelUpdater(node, val); new Watcher(this.vm,exp,function(value){ self.modelUpdater(node,value); }) node.addEventListener('input',function(e){ var newValue = e.target.value; if(newValue===val){ return } self.vm[exp] = newValue; val = newValue; }) }, updateText: function(node,text){ node.textContent = typeof text === 'undefined' ? '' : text; }, modelUpdater: function(node,text){ node.value = typeof text === 'undefined' ? '' : text; }, isTextNode: function(node){ return node.nodeType === 3; }, isElementNode: function(node){ return node.nodeType === 1; }, isDirective: function(directive){ return directive.indexOf('v-')===0; }, isEventDirentive: function(directive){ return directive.indexOf('on:')===0; } } function SelfVue(options){ var self = this; this.data = options.data; this.methods = options.methods; Object.keys(this.data).forEach(key=>{ self.proxyKey(key); }) observe(this.data); new Compile(options.el,this); options.mounted.call(this); } SelfVue.prototype.proxyKey = function(key){ var self = this; Object.defineProperty(self,key,{ get: function(){ return self.data[key]; }, set: function(newVal){ self.data[key] = newVal; } }) } var selfVue = new SelfVue({ el: '#app', data: { title: 'hello world', name: 'canfoo' }, methods: { clickMe: function () { this.title = 'hello world'; } }, mounted: function () { window.setTimeout(() => { this.title = '你好'; }, 1000); } }) </script> </body> </html>
The text was updated successfully, but these errors were encountered:
No branches or pull requests
The text was updated successfully, but these errors were encountered: