手写Vue2双向数据绑定

157 阅读2分钟

Vue2双向数据绑定的实现基于Object.defineProperty()方法,它可以为一个对象定义属性,并在属性被读取或设置时触发相应的操作。具体步骤如下:

  1. 定义一个Vue实例,其中包含需要双向绑定的数据对象data和DOM元素el。
  2. 遍历data对象中的每个属性,为其添加get和set方法,用于在属性被读取或设置时更新DOM元素。
  3. 在set方法中,首先保存新值并判断是否发生变化,若变化则触发更新函数update。
  4. 在update函数中,执行DOM更新操作,将新值赋给DOM元素的value属性。
  5. 给DOM元素添加事件监听器,当其值改变时,更新data对象中对应属性的值。

下面是一个简单的示例代码:

// 定义Vue类
class Vue {
  constructor(options) {
    this._data = options.data;
    this._el = document.querySelector(options.el);
    this._binding = {};

    // 遍历data对象
    for (let key in this._data) {
      this._binding[key] = [];

      Object.defineProperty(this._data, key, {
        get: function() {
          return this['_'+key];
        },
        set: function(value) {
          if (this['_'+key] !== value) {
            this['_'+key] = value;
            this._binding[key].forEach(function(item) {
              item.update();
            });
          }
        }
      });

      this['_'+key] = this._data[key];
    }

    this._compile(this._el);
  }

  // 编译DOM元素
  _compile(root) {
    let nodes = root.children;
    for (let i = 0; i < nodes.length; i++) {
      let node = nodes[i];
      if (node.children.length) {
        this._compile(node);
      }

      if (node.hasAttribute('v-model')) {
        let attrValue = node.getAttribute('v-model');
        this._binding[attrValue].push(new Watcher(this, node, attrValue, 'value'));
        node.addEventListener('input', function() {
          let value = this.value;
          this._vm._data[attrValue] = value;
        });
      }
    }
  }
}

// 定义Watcher类
class Watcher {
  constructor(vm, node, name, nodeType) {
    this._vm = vm;
    this._node = node;
    this._name = name;
    this._nodeType = nodeType;
    this.update();
  }

  update() {
    this._node[this._nodeType] = this._vm._data[this._name];
  }
}

// 使用Vue类创建实例
let vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello, Vue!'
  }
});

在上面的代码中,我们使用Object.defineProperty()方法为data对象的每个属性添加了get和set方法,并将其保存在_binding中。然后,在_compile()方法中遍历DOM树,为含有v-model属性的元素添加事件监听器,并创建一个Watcher实例来更新对应的DOM元素。最后,在set方法中触发更新函数update,将新值赋给对应的DOM元素。这就实现了Vue2双向数据绑定的基本功能。