1 <html> 2 <head> 3 <meta charset="UTF-8" /> 4 <meta 5 name="viewport" 6 content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" 7 /> 8 <meta http-equiv="X-UA-Compatible" content="ie=edge" /> 9 <title>proxyVue</title> 10 <style> 11 #app { 12 margin: 100px auto 0 auto; 13 300px; 14 } 15 #btn { 16 margin: 10px auto; 17 } 18 </style> 19 </head> 20 <body> 21 <div id="app"> 22 <input type="text" v-model="num" /> 23 <input id="btn" type="button" value="添加到Todolist" v-click="addList" /><br/> 24 <span>您输入的是:</span><span v-bind="num"></span> 25 <ul id="list"></ul> 26 </div> 27 </body> 28 29 <script> 30 class proxyVue { 31 constructor(options) { 32 this.$options = options || {}; 33 this.$methods = this._methods = this.$options.methods; 34 const data = (this._data = this.$options.data); 35 this.subscribe = {}; 36 this.observe(data); 37 this.compile(options.el); 38 } 39 publish(watcher) { 40 if (!this.subscribe[watcher.property]) 41 this.subscribe[watcher.property] = []; 42 this.subscribe[watcher.property].push(watcher); 43 } 44 observe(data) { 45 const that = this; 46 let handler = { 47 get(target, property) { 48 return target[property]; 49 }, 50 set(target, property, value) { 51 let res = Reflect.set(target, property, value); 52 that.subscribe[property].map(item => { 53 item.update(); 54 }); 55 return res; 56 } 57 }; 58 this.$data = new Proxy(data, handler); 59 } 60 compile(el) { 61 const nodes = Array.prototype.slice.call( 62 document.querySelector(el).children 63 ); 64 let data = this.$data; 65 nodes.map(node => { 66 if (node.children.length > 0) this._complie(node); 67 if (node.hasAttribute("v-bind")) { 68 let property = node.getAttribute("v-bind"); 69 this.publish(new Watcher(node, "innerHTML", data, property)); 70 } 71 if (node.hasAttribute("v-model")) { 72 let property = node.getAttribute("v-model"); 73 this.publish(new Watcher(node, "value", data, property)); 74 node.addEventListener("input", () => { 75 data[property] = node.value; 76 }); 77 } 78 if (node.hasAttribute("v-click")) { 79 let methodName = node.getAttribute("v-click"); 80 let mothod = this.$methods[methodName].bind(data); 81 node.addEventListener("click", mothod); 82 } 83 }); 84 } 85 } 86 class Watcher { 87 constructor(node, attr, data, property) { 88 this.node = node; 89 this.attr = attr; 90 this.data = data; 91 this.property = property; 92 } 93 update() { 94 this.node[this.attr] = this.data[this.property]; 95 } 96 } 97 // 渲染todolist列表 98 const Render = { 99 // 初始化 100 init: function(arr) { 101 const fragment = document.createDocumentFragment(); 102 for (let i = 0; i < arr.length; i++) { 103 const li = document.createElement("li"); 104 li.textContent = arr[i]; 105 fragment.appendChild(li); 106 } 107 list.appendChild(fragment); 108 }, 109 addList: function(val) { 110 const li = document.createElement("li"); 111 li.textContent = val; 112 list.appendChild(li); 113 } 114 }; 115 // 实例化一个proxyVue 116 window.onload = function() { 117 let vm = new proxyVue({ 118 el: "#app", 119 data: { 120 num: 0, 121 arr: [] 122 }, 123 methods: { 124 addList() { 125 this.arr.push(this.num); 126 Render.addList(this.num); 127 } 128 } 129 }); 130 }; 131 </script> 132 </html> 133 摘自https://github.com/nightzing/vue3-Proxy/blob/master/proxyVue.html 134