1. 1 我们看到的变量,其实都不是独立的,它们都是windows对象上的属性
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 var a = 117; 12 console.log(a); 13 console.log(window.a); 14 </script> 15 </body> 16 </html>
运行结果:直接打印a 和 打印window下的a 结果一样
1.2 defineProperty(): 每个对象在对本身属性的设置或者调用时,都会调用set()或则get()函数;这个和php类的调用差不多,在php中,叫做魔术方法,在调用类时,会调用__construct()方法,在结束调用时,会调用__destruct() 方法;
1 <script> 2 var obj = {}; 3 Object.defineProperty(obj, 'name1', { 4 set: function() { 5 console.log("set()方法被调用了"); 6 }, 7 get: function() { 8 console.log("get()方法被调用了"); 9 } 10 }); 11 var a = obj.name1; // 调用get()方法 12 obj.name1 = "huanying2015"; // 调用set()方法 13 </script>
运行结果:
2. 对obj对象的属性进行监控,当属性改变时,调用set方法:其实这里监控的也不是obj的属性,而是监控输入框value值的变换,通过keyup 事件来监控
1 <head> 2 <meta charset="UTF-8"> 3 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 4 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 5 <title>Document</title> 6 <script> 7 window.onload = function() { 8 var OInput = document.querySelector("#aa"); 9 var Odiv = document.querySelector("#bb"); 10 var obj = {}; 11 Object.defineProperty(obj, 'content', { 12 set: function(val) { 13 OInput.value = val; 14 Odiv.innerHTML = val; 15 }, 16 }); 17 // e.target.value获取的就是你选择接受事件的元素输入的或者选择的值。 18 // 参数e接收事件对象。 19 // 而事件对象也有很多属性和方法, 其中target属性是获取触发事件对象的目标, 也就是绑定事件的元素, 20 // e.target表示该DOM元素, 然后在获取其相应的属性值。 21 OInput.addEventListener('keyup', function(e) { 22 obj.content = e.target.value; 23 }); 24 } 25 </script> 26 </head> 27 <body> 28 <input type="text" id="aa"> 29 <div id="bb"></div> 30 </body>
运行结果:
3. 双向绑定预热之------碎片节点说明:创建一个碎片节点---->然后在id 为box的范围内查找节点,把所有的节点都插入到碎片节点中,然后在把碎片节点插入到id为box 的范围内,即先把 id = box 中的东西拿出来,然后玩一玩,检查一下,再把东西放回去
注意:DocumentFragment节点不属于文档树,继承的parentNode属性总是null。它有一个很实用的特点,当请求把一个DocumentFragment节点插入文档树时,插入的不是DocumentFragment自身,而是它的所有子孙节点。
1 <body> 2 <div id="box"> 3 <input type="text" id="txt"> 4 <span id="box2"></span> 5 </div> 6 <script> 7 function nodeToFragment(node) { 8 var frag = document.createDocumentFragment(); 9 var childNode; 10 // 这里childNode 和node.firstChild 都同时指向node 的第一个节点,放在while 中,是作为一个判断语句使用, 11 // 如果node.firstChild 为true ,即有第一个节点,那么执行do的内容(while(true){do;}),如果没有第一个节点,那么终止循环 12 while (childNode = node.firstChild) { 13 // 1.把node的第一个子节点插入碎片节点中 14 // 2.注意注意: 15 // 3.有一个很重要的特性是,如果使用appendChid方法将原dom树中的节点添加到DocumentFragment中时,会删除原来的节点。 16 // 4.以上的第3点是while循环的基础:所以每次循环,node.firstChild 都指向不同的节点,直到循环完毕 17 frag.appendChild(childNode); 18 } 19 return frag; 20 } 21 var oBox = document.querySelector("#box"); 22 var nodeList = nodeToFragment(oBox); 23 // 把原先被删除的节点重新一次性插入原处,当插入的节点比较多时,这可以调高效率,减少页面对DOM的渲染次数 24 oBox.appendChild(nodeList); 25 </script> 26 </body>
运行结果:
4. 绑定编译原理:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 <script> 9 window.onload = function() { 10 // 替换函数:对html 中的content 进行替换 11 function compile(node, ghost) { 12 // 当需要替换的节点为元素节点时(即节点类型 nodeType ==1),遍历元素中的属性节点,查找元素中有没有'v-model'属性,如果有,则进行替换 13 if (node.nodeType == 1) { 14 // 获取元素的所有属性,使用attributes属性获取 15 var attrs = node.attributes; 16 for (var i = 0, len = attrs.length; i < len; i++) { 17 // 当元素的属性名字为‘v-model’时 18 if (attrs[i].nodeName == "v-model") { 19 // 获取'v-model'属性的属性值,存在key中 20 var key = attrs[i].nodeValue; 21 // 设置元素节点的value 属性为 ghost.data.key // 所有的.都可以使用[]来替代// 22 node.value = ghost.data[key]; 23 // 清除元素中的 ‘v-mdel’属性 24 node.removeAttribute('v-model'); 25 } 26 } 27 }; 28 // 设置正则匹配 29 var re = /{{(.*)?}}/; 30 // 如果为文本节点,即属性值为3时, 31 if (node.nodeType == 3) { 32 // 查找文本节点的值,如果匹配正则 33 if (re.test(node.nodeValue)) { 34 // 获取正则中的第一个匹配对象,即{{}}中的内容 35 var key = RegExp.$1; 36 // 清除两侧的空格 37 key = key.trim(); 38 // 将文本内容替换为 ghost.data[key]; 39 node.nodeValue = ghost.data[key]; 40 } 41 } 42 }; 43 // 替换函数 44 function nodeToFragment(node, ghost) { 45 var flag = document.createDocumentFragment(); 46 var childNode; 47 while (childNode = node.firstChild) { 48 compile(childNode, ghost); 49 flag.appendChild(childNode); 50 } 51 return flag; 52 }; 53 // 传值函数 54 function Ghost(opt) { 55 this.data = opt.data; 56 var id = opt.el; 57 var Obox = document.querySelector(id); 58 var node = nodeToFragment(Obox, this); 59 Obox.appendChild(node); 60 } 61 // 实例化函数,这里相当于在vue.js 中的 new Vue({}); 62 new Ghost({ 63 el: "#box", 64 data: { 65 content: 'hello,huanying2015,how are you?' 66 } 67 }); 68 } 69 </script> 70 </head> 71 <body> 72 <div id="box"> 73 <input type="text" id="txt" v-model="content"> 74 <br> {{content}} 75 </div> 76 </body> 77 </html>
运行结果:
5.相应式绑定数据:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 <script> 9 window.onload = function() { 10 function responsive(obj, key, val) { 11 Object.defineProperty(obj, key, { 12 get: function() { 13 return val; 14 }, 15 set: function(newVal) { 16 if (val == newVal) { 17 return; 18 }; 19 val = newVal; 20 console.log('值改变了,新值为:' + val); 21 } 22 }); 23 }; 24 25 function observe(obj, ghost) { 26 Object.keys(obj).forEach(function(key) { 27 responsive(ghost, key, obj[key]); 28 }); 29 }; 30 // 替换函数:对html 中的content 进行替换 31 function compile(node, ghost) { 32 // 当需要替换的节点为元素节点时(即节点类型 nodeType ==1),遍历元素中的属性节点,查找元素中有没有'v-model'属性,如果有,则进行替换 33 if (node.nodeType == 1) { 34 // 获取元素的所有属性,使用attributes属性获取 35 var attrs = node.attributes; 36 for (var i = 0, len = attrs.length; i < len; i++) { 37 // 当元素的属性名字为‘v-model’时 38 if (attrs[i].nodeName == "v-model") { 39 var key = attrs[i].nodeValue; 40 // 这里 ghost[key] 只是一个中间变量 41 // 监控键盘松开事件,当键盘松开时,在ghost上增加一个属性key,然后获取监听目标的值,把它赋值给ghost[key] 42 node.addEventListener('keyup', function(ev) { 43 ghost[key] = ev.target.value; 44 }); 45 // 然后把这个ghost[key]赋值给节点的value 属性 46 node.value = ghost[key]; 47 // 删除属性节点‘v-model’ 48 node.removeAttribute('v-model'); 49 } 50 } 51 }; 52 // 设置正则匹配 53 var re = /{{(.*)?}}/; 54 // 如果为文本节点,即属性值为3时, 55 if (node.nodeType == 3) { 56 // 查找文本节点的值,如果匹配正则 57 if (re.test(node.nodeValue)) { 58 // 获取正则中的第一个匹配对象,即{{}}中的内容 59 var key = RegExp.$1; 60 // 清除两侧的空格 61 key = key.trim(); 62 // 将文本内容替换为 ghost.data[key]; 63 node.nodeValue = ghost.data[key]; 64 } 65 } 66 }; 67 // 替换函数 68 function nodeToFragment(node, ghost) { 69 var flag = document.createDocumentFragment(); 70 var childNode; 71 while (childNode = node.firstChild) { 72 compile(childNode, ghost); 73 flag.appendChild(childNode); 74 } 75 return flag; 76 }; 77 // 传值函数 78 function Ghost(opt) { 79 this.data = opt.data; 80 var data = this.data; 81 var id = opt.el; 82 // 对当前对象及当前对象的data 数据对象进行监控 83 observe(data, this); 84 var Obox = document.querySelector(id); 85 var node = nodeToFragment(Obox, this); 86 Obox.appendChild(node); 87 } 88 // 实例化函数,这里相当于在vue.js 中的 new Vue({}); 89 new Ghost({ 90 el: "#box", 91 data: { 92 content: 'hello,huanying2015,how are you?' 93 } 94 }); 95 } 96 </script> 97 </head> 98 <body> 99 <div id="box"> 100 <input type="text" id="txt" v-model="content"> 101 <br> {{content}} 102 </div> 103 </body> 104 </html>
运行结果:
6. 发布者,订阅者模式解析:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 <script> 9 // 发布者1 发布信息 10 sub1 = { 11 update: function() { 12 console.log("这是发布者1发出的信息"); 13 } 14 } 15 // 发布者2 发布信息 16 sub2 = { 17 update: function() { 18 console.log("这是发布者2发出的信息"); 19 } 20 } 21 // 发布者3 发布信息 22 sub3 = { 23 update: function() { 24 console.log("这是发布者3发出的信息"); 25 } 26 } 27 //发布清单构造函数 28 function Dep() { 29 this.subs = [sub1, sub2, sub3]; 30 } 31 // 发布清单原型对象上加nodify()方法 32 Dep.prototype.nodify = function() { 33 this.subs.forEach(function(sub) { 34 // 执行发布框架操作 35 sub.update(); 36 }); 37 } 38 // 实例化发布清单,即填写发布清单 39 var dep = new Dep(); 40 // 一个实体指定出一套自己的发布方法 41 var pub = { 42 publish: function() { 43 // 发布方法中,执行发布清单的操作 44 dep.nodify(); 45 } 46 } 47 // 发布执行 48 pub.publish(); 49 </script> 50 </head> 51 <body> 52 </body> 53 </html>
运行结果:
7. 响应式数据绑定:即输入的同时,显示输出
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 <script> 9 window.onload = function() { 10 var Watcher = function(ghost, node, name) { 11 Dep.target = this; 12 this.name = name; 13 this.node = node; 14 this.ghost = ghost; 15 this.update(); 16 Dep.target = null; 17 } 18 Watcher.prototype = { 19 update: function() { 20 this.get(); 21 this.node.nodeValue = this.value; 22 }, 23 get: function() { 24 this.value = this.ghost[this.name]; 25 } 26 } 27 28 function Dep() { 29 this.subs = []; 30 } 31 Dep.prototype = { 32 addsub: function(sub) { 33 this.subs.push(sub); 34 }, 35 nodify: function() { 36 this.subs.forEach(function(sub) { 37 sub.update(); 38 }); 39 } 40 } 41 42 function responsive(obj, key, val) { 43 var dep = new Dep(); 44 Object.defineProperty(obj, key, { 45 get: function() { 46 if (Dep.target) { 47 dep.addsub(Dep.target); 48 } 49 console.log("access:" + val); 50 return val; 51 }, 52 set: function(newVal) { 53 if (val == newVal) { 54 return; 55 } 56 val = newVal; 57 console.log("值改变了:" + val); 58 dep.nodify(); 59 } 60 }); 61 } 62 63 function observe(obj, ghost) { 64 Object.keys(obj).forEach(function(key) { 65 responsive(ghost, key, obj[key]); 66 }); 67 } 68 69 function compile(node, ghost) { 70 var re = /{{(.*)}}/; 71 if (node.nodeType == 1) { 72 var attrs = node.attributes; 73 for (var i = 0, len = attrs.length; i < len; i++) { 74 if (attrs[i].nodeName == "v-model") { 75 var key = attrs[i].nodeValue; 76 node.addEventListener("keyup", function(ev) { 77 ghost[key] = ev.target.value; 78 }); 79 node.value = ghost[key]; 80 node.removeAttribute("v-model"); 81 } 82 } 83 } 84 if (node.nodeType == 3) { 85 if (re.test(node.nodeValue)) { 86 var key = RegExp.$1; 87 key = key.trim(); 88 new Watcher(ghost, node, key); 89 } 90 } 91 } 92 93 function nodeToFragment(node, ghost) { 94 var flag = document.createDocumentFragment(); 95 var childNode; 96 while (childNode = node.firstChild) { 97 compile(childNode, ghost); 98 flag.appendChild(childNode); 99 } 100 return flag; 101 } 102 103 function Ghost(opt) { 104 this.data = opt.data; 105 var data = this.data; 106 observe(data, this); 107 var id = opt.el; 108 var obox = document.querySelector(id); 109 var node = nodeToFragment(obox, this); 110 obox.appendChild(node); 111 } 112 var ogt = new Ghost({ 113 el: "#box", 114 data: { 115 content: "huanying2015", 116 msg: "ahifahha", 117 } 118 }); 119 } 120 </script> 121 </head> 122 <body> 123 <div class="box" id="box"> 124 <input type="text" id="tet" v-model="content"><br> {{content}} 125 </div> 126 </body> 127 </html>
运行结果: