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>
运行结果: