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 width: 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