zoukankan      html  css  js  c++  java
  • vue的双向数据绑定

      这篇文章我会仿照vue写一个双向绑定的实例,主要实v-model  ,  v-bind  ,  v-click

    1、原理

      Vue的双向数据绑定的原理大家可能或多或少了解一点,主要是通过 Object 对象的 defineProperty 属性,重写data的 set 和 get 函数来实现的。

      

    2、页面结构

      

    包含了 

    1. 一个input,使用v-model指令

    2. 一个button,使用v-click指令

    3. 一个h3,使用v-bind指令。

     我们最后会通过类似于vue的方式来使用我们的双向数据绑定,结合我们的数据结构添加注释:

     首先我们需要定义一个myVue构造函数:

    为了初始化这个构造函数,给它添加一个 _init 属性:

    接下来实现 _obverse 函数,对data进行处理,重写data的set和get函数:

    并改造_init函数

     接下来我们写一个指令类Watcher,用来绑定更新函数,实现对DOM元素的更新。

     

    更新 _init 函数以及 \_obverse 函数:

    那么如何将view与model进行绑定呢?接下来我们定义一个 _compile 函数,用来解析我们的指令(v-bind,v-model,v-clickde)等,并在这个过程中对view与model进行绑定。

    至此,我们已经实现了一个简单vue的双向绑定功能,包括v-bind, v-model, v-click三个指令。效果如下图:

       

    附上全部代码

      1 <!DOCTYPE html>
      2 
      3 <head>
      4 
      5  <title>myVue</title>
      6 
      7 </head>
      8 
      9 <style>
     10 
     11  #app {
     12 
     13    text-align: center;
     14 
     15  }
     16 
     17 </style>
     18 
     19 <body>
     20 
     21  <div id="app">
     22 
     23    <form>
     24 
     25      <input type="text"  v-model="number">
     26 
     27      <button type="button" v-click="increment">增加</button>
     28 
     29    </form>
     30 
     31    <h3 v-bind="number"></h3>
     32 
     33  </div>
     34 
     35 </body>
     36 
     37 <script>
     38 
     39  function myVue(options) {
     40 
     41    this._init(options);
     42 
     43  }
     44 
     45  myVue.prototype._init = function (options) {
     46 
     47    this.$options = options;
     48 
     49    this.$el = document.querySelector(options.el);
     50 
     51    this.$data = options.data;
     52 
     53    this.$methods = options.methods;
     54 
     55    this._binding = {};
     56 
     57    this._obverse(this.$data);
     58 
     59    this._complie(this.$el);
     60 
     61  }
     62 
     63  myVue.prototype._obverse = function (obj) {
     64 
     65    var value;
     66 
     67    for (key in obj) {
     68 
     69      if (obj.hasOwnProperty(key)) {
     70 
     71        this._binding[key] = {                                                                                                                                                          
     72 
     73          _directives: []
     74 
     75        };
     76 
     77        value = obj[key];
     78 
     79        if (typeof value === 'object') {
     80 
     81          this._obverse(value);
     82 
     83        }
     84 
     85        var binding = this._binding[key];
     86 
     87        Object.defineProperty(this.$data, key, {
     88 
     89          enumerable: true,
     90 
     91          configurable: true,
     92 
     93          get: function () {
     94 
     95            console.log(`获取${value}`);
     96 
     97            return value;
     98 
     99          },
    100 
    101          set: function (newVal) {
    102 
    103            console.log(`更新${newVal}`);
    104 
    105            if (value !== newVal) {
    106 
    107              value = newVal;
    108 
    109              binding._directives.forEach(function (item) {
    110 
    111                item.update();
    112 
    113              })
    114 
    115            }
    116 
    117          }
    118 
    119        })
    120 
    121      }
    122 
    123    }
    124 
    125  }
    126 
    127  myVue.prototype._complie = function (root) {
    128 
    129    var _this = this;
    130 
    131    var nodes = root.children;
    132 
    133    for (var i = 0; i < nodes.length; i++) {
    134 
    135      var node = nodes[i];
    136 
    137      if (node.children.length) {
    138 
    139        this._complie(node);
    140 
    141      }
    142 
    143      if (node.hasAttribute('v-click')) {
    144 
    145        node.onclick = (function () {
    146 
    147          var attrVal = nodes[i].getAttribute('v-click');
    148 
    149          return _this.$methods[attrVal].bind(_this.$data);
    150 
    151        })();
    152 
    153      }
    154 
    155      if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) {
    156 
    157        node.addEventListener('input', (function(key) {
    158 
    159          var attrVal = node.getAttribute('v-model');
    160 
    161          _this._binding[attrVal]._directives.push(new Watcher(
    162 
    163            'input',
    164 
    165            node,
    166 
    167            _this,
    168 
    169            attrVal,
    170 
    171            'value'
    172 
    173          ))
    174 
    175          return function() {
    176 
    177            _this.$data[attrVal] =  nodes[key].value;
    178 
    179          }
    180 
    181        })(i));
    182 
    183      } 
    184 
    185      if (node.hasAttribute('v-bind')) {
    186 
    187        var attrVal = node.getAttribute('v-bind');
    188 
    189        _this._binding[attrVal]._directives.push(new Watcher(
    190 
    191          'text',
    192 
    193          node,
    194 
    195          _this,
    196 
    197          attrVal,
    198 
    199          'innerHTML'
    200 
    201        ))
    202 
    203      }
    204 
    205    }
    206 
    207  }
    208 
    209  function Watcher(name, el, vm, exp, attr) {
    210 
    211    this.name = name;         //指令名称,例如文本节点,该值设为"text"
    212 
    213    this.el = el;             //指令对应的DOM元素
    214 
    215    this.vm = vm;             //指令所属myVue实例
    216 
    217    this.exp = exp;           //指令对应的值,本例如"number"
    218 
    219    this.attr = attr;         //绑定的属性值,本例为"innerHTML"
    220 
    221    this.update();
    222 
    223  }
  • 相关阅读:
    SQL Server的AlwaysOn错误19456和41158
    kvm上的Linux虚拟机使用virtio磁盘
    利用HAProxy代理SQL Server的AlwaysOn辅助副本
    KVM安装部署
    ola.hallengren的SQL Server维护脚本
    在单链表的第i个位置后插入一个节点(阿里+腾讯等面试题总结)
    怎么发现RAC环境中&#39;library cache pin&#39;等待事件的堵塞者(Blocker)?
    php unserialize 返回false的解决方法
    千万别让这些举动断送了你的职业前程-好文共分享
    Android开发:仿美团下拉列表菜单,帮助类,复用简单
  • 原文地址:https://www.cnblogs.com/gongyijie/p/9280662.html
Copyright © 2011-2022 走看看