转:mvvm原理

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4   <meta charset="UTF-8">
  5   <title>Two-way-data-binding</title>
  6 </head>
  7 <body>
  8   
  9   <div id="app">
 10     <input type="text" v-model="text">
 11     {{ text }}
 12   </div>
 13 
 14   <script>
 15     function observe (obj, vm) {
 16       Object.keys(obj).forEach(function (key) {
 17         defineReactive(vm, key, obj[key]);
 18       })
 19     }
 20     function defineReactive (obj, key, val) {
 21       var dep = new Dep();
 22       Object.defineProperty(obj, key, {
 23         get: function () {
 24           // 添加订阅者 watcher 到主题对象 Dep
 25           if (Dep.target) dep.addSub(Dep.target);
 26           return val
 27         },
 28         set: function (newVal) {
 29           if (newVal === val) return
 30           val = newVal;
 31           // 作为发布者发出通知
 32           dep.notify();
 33         }
 34       });
 35     }
 36     function nodeToFragment (node, vm) {
 37       var flag = document.createDocumentFragment();
 38       var child;
 39       // 许多同学反应看不懂这一段,这里有必要解释一下
 40       // 首先,所有表达式必然会返回一个值,赋值表达式亦不例外
 41       // 理解了上面这一点,就能理解 while (child = node.firstChild) 这种用法
 42       // 其次,appendChild 方法有个隐蔽的地方,就是调用以后 child 会从原来 DOM 中移除
 43       // 所以,第二次循环时,node.firstChild 已经不再是之前的第一个子元素了
 44       while (child = node.firstChild) {
 45         compile(child, vm);
 46         flag.appendChild(child); // 将子节点劫持到文档片段中
 47       }
 48       return flag
 49     }
 50     function compile (node, vm) {
 51       var reg = /\{\{(.*)\}\}/;
 52       // 节点类型为元素
 53       if (node.nodeType === 1) {
 54         var attr = node.attributes;
 55         // 解析属性
 56         for (var i = 0; i < attr.length; i++) {
 57           if (attr[i].nodeName == 'v-model') {
 58             var name = attr[i].nodeValue; // 获取 v-model 绑定的属性名
 59             node.addEventListener('input', function (e) {
 60               // 给相应的 data 属性赋值,进而触发该属性的 set 方法
 61               vm[name] = e.target.value;
 62             });
 63             node.value = vm[name]; // 将 data 的值赋给该 node
 64             node.removeAttribute('v-model');
 65           }
 66         };
 67         new Watcher(vm, node, name, 'input');
 68       }
 69       // 节点类型为 text
 70       if (node.nodeType === 3) {
 71         if (reg.test(node.nodeValue)) {
 72           var name = RegExp.$1; // 获取匹配到的字符串
 73           name = name.trim();
 74           new Watcher(vm, node, name, 'text');
 75         }
 76       }
 77     }
 78     function Watcher (vm, node, name, nodeType) {
 79       Dep.target = this;
 80       this.name = name;
 81       this.node = node;
 82       this.vm = vm;
 83       this.nodeType = nodeType;
 84       this.update();
 85       Dep.target = null;
 86     }
 87     Watcher.prototype = {
 88       update: function () {
 89         this.get();
 90         if (this.nodeType == 'text') {
 91           this.node.nodeValue = this.value;
 92         }
 93         if (this.nodeType == 'input') {
 94           this.node.value = this.value;
 95         }
 96       },
 97       // 获取 data 中的属性值
 98       get: function () {
 99         this.value = this.vm[this.name]; // 触发相应属性的 get
100       }
101     }
102     function Dep () {
103       this.subs = []
104     }
105     Dep.prototype = {
106       addSub: function(sub) {
107         this.subs.push(sub);
108       },
109       notify: function() {
110         this.subs.forEach(function(sub) {
111           sub.update();
112         });
113       }
114     }
115     function Vue (options) {
116       this.data = options.data;
117       var data = this.data;
118       observe(data, this);
119       var id = options.el;
120       var dom = nodeToFragment(document.getElementById(id), this);
121       // 编译完成后,将 dom 返回到 app 中
122       document.getElementById(id).appendChild(dom); 
123     }
124     var vm = new Vue({
125       el: 'app',
126       data: {
127         text: 'hello world'
128       }
129     })
130   </script>
131 </body>
132 </html>

自己也写了一份,但是,dom对象到view这一层并没有实现

posted on 2018-04-25 11:36  Newbies  阅读(285)  评论(0)    收藏  举报

导航