• vue.js 中双向绑定的实现---初级


    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>

    运行结果:

  • 相关阅读:
    Andorid自定义attr的各种坑
    git 使用那些事儿
    Gradle task
    他们要消失了吗?探访人工智能浪潮下的鉴黄师
    测试环境docker化—容器集群编排实践
    测试环境docker化(一)—基于ndp部署模式的docker基础镜像制作
    后台服务项目的白盒测试之旅
    利用反向代理测应用的流量
    CCF 201312-5 I’m stuck! (暴力,BFS)
    CodeForces 709C Letters Cyclic Shift (水题)
  • 原文地址:https://www.cnblogs.com/huanying2015/p/8540475.html
Copyright © 2020-2023  润新知