Vue2双向绑定demo实现
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> 测试双向绑定demo <input type="text" v-model="textMy" /> {{textMy}} </div> </body> <script type="text/javascript"> //编译函数 function compile(node, vm) { var reg = /\{\{(.*)\}\}/; // 来匹配{{xxx}}中的xxx //如果是元素节点 if(node.nodeType === 1) { var attr = node.attributes; //解析元素节点的所有属性 for(let i = 0; i < attr.length; i++) { if(attr[i].nodeName == 'v-model') { var name = attr[i].nodeValue //看看是与哪一个数据相关 node.addEventListener('input', function(e) { //将与其相关的数据改为最新值 vm[name] = e.target.value }) node.value = vm.data[name]; //将data中的值赋予给该node node.removeAttribute('v-model') } } } //如果是文本节点 if(node.nodeType === 3) { if(reg.test(node.nodeValue)) { var name = RegExp.$1; //获取到匹配的字符串 name = name.trim(); node.nodeValue = vm[name]; //将data中的值赋予给该node new Watcher(vm, node, name) //绑定一个订阅者 } } } // 在向碎片化文档中添加节点时,每个节点都处理一下 function nodeToFragment(node, vm) { var fragment = document.createDocumentFragment(); var child; while(child = node.firstChild) { compile(child, vm); fragment.appendChild(child); } return fragment } // Vue构造函数 // 观察data中的所有属性值,注意增添了observe function Vue(options) { this.data = options.data; observe(this.data, this) var id = options.el; var dom = nodeToFragment(document.getElementById(id), this) //处理完所有节点后,重新把内容添加回去 document.getElementById(id).appendChild(dom) } //实现一个响应式监听属性的函数。一旦有赋新值就发生变化 function defineReactive(obj, key, val) { var dep = new Dep(); //观察者实例 Object.defineProperty(obj, key, { get: function() { 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(); this.node.nodeValue = this.value //更改节点内容的关键 }, get() { this.value = this.vm[this.name] //触发相应的get } } //dep构造函数 function Dep() { this.subs = [] // 观察主题添加订阅者 } Dep.prototype = { // 添加订阅者 addSub(sub) { this.subs.push(sub) }, // 发布通知 notify() { this.subs.forEach(function(sub) { sub.update(); }) } } var vm = new Vue({ el: 'app', data: { textMy: '礼记' } }) </script> </html>
本文来自博客园,作者:122www,转载请注明原文链接:https://www.cnblogs.com/131362wsc/p/18267532