模拟VUE2的双向绑定简单实现

210 阅读1分钟
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>模拟VUE双向绑定实现</title>
  <style>
    #app {
      background: #eee;
    }
  </style>
</head>
<body>
<div id="app"></div>

<script>
  var app = document.getElementById("app");
  var isEnd = true;

  function bindDom() {
    var input1 = document.getElementById("input1");
    input1.addEventListener("compositionstart", function () {
      console.log("开始输入中文");
      isEnd = false;
    });
    input1.addEventListener("compositionend", function () {
      isEnd = true;
      console.log("结束输入中文");
    });
    input1.addEventListener("input", function (e) {
      setTimeout(function () {
        console.log("触发input");
        if(isEnd){
          inputChange(e.target);
        }
      }, 0)
    });
  }

  function inputChange(dm) {
    console.log(dm)
    var pos = dm.selectionEnd;
    vm.data.inputValue = dm.value;
    console.log(pos);

    var input1 = document.getElementById("input1");
    input1.focus();
    input1.setSelectionRange(pos, pos);
  }

  var tpl = '<input id="input1" type="text" value="{{inputValue}}"><div>{{inputValue}}</div>';


  function Vue() {
    this.data = {
      inputValue: 0
    };
  }

  var vm = new Vue();

  Object.keys(vm.data).forEach(function (key) {
    vm.data['_' + key] = vm.data[key];
    Object.defineProperty(vm.data, key, {
      get: function() {
        console.log("读取", this['_' + key]);
        return this['_' + key];
      },
      set: function(value) {
        console.log("设置", value);
        this['_' + key] = value;
        app.innerHTML = Template(tpl, vm.data);
        bindDom();
      }
    });
  });

  var Template = function (tpl, data) {
    var pattern = /\{\{([^\}\}]+)?\}\}/g;
    var body = "return '";
    body += tpl.replace(pattern, function (m, g) {
      return "' + this." + g.trim() + " + '";
    });
    body += "';";
    return new Function(body.replace(/[\t\n\r]/g, '')).apply(data);
  };

  app.innerHTML = Template(tpl, vm.data);

  bindDom();
</script>
</body>
</html>