当前位置:首页 > VUE

vue双向绑定实现

2026-01-19 04:12:11VUE

Vue 双向绑定实现原理

Vue 的双向绑定主要通过 v-model 指令实现,其核心是结合数据劫持(Object.definePropertyProxy)和发布-订阅模式。

数据劫持

Vue 2.x 使用 Object.defineProperty 劫持对象的属性,通过 gettersetter 监听数据变化:

vue双向绑定实现

let data = { value: '' };
Object.defineProperty(data, 'value', {
  get() {
    return this._value;
  },
  set(newVal) {
    this._value = newVal;
    console.log('数据更新了');
  }
});

Vue 3.x 改用 Proxy 实现更全面的拦截:

let data = { value: '' };
let proxy = new Proxy(data, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    target[key] = value;
    console.log('数据更新了');
    return true;
  }
});

发布-订阅模式

通过 Dep(依赖收集器)和 Watcher(观察者)实现视图更新:

vue双向绑定实现

class Dep {
  constructor() {
    this.subscribers = [];
  }
  depend() {
    if (target && !this.subscribers.includes(target)) {
      this.subscribers.push(target);
    }
  }
  notify() {
    this.subscribers.forEach(sub => sub());
  }
}

let dep = new Dep();
let target = null;

function watcher(fn) {
  target = fn;
  dep.depend();
  fn();
  target = null;
}

v-model 的实现

v-model 是语法糖,本质上是 :value@input 的组合:

<input v-model="message">
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value">

完整实现示例

以下是一个简化版的双向绑定实现:

class Vue {
  constructor(options) {
    this.$data = options.data;
    this.observe(this.$data);
    this.compile(options.el);
  }

  observe(data) {
    Object.keys(data).forEach(key => {
      let value = data[key];
      const dep = new Dep();
      Object.defineProperty(data, key, {
        get() {
          if (Dep.target) dep.addSub(Dep.target);
          return value;
        },
        set(newVal) {
          value = newVal;
          dep.notify();
        }
      });
    });
  }

  compile(el) {
    const element = document.querySelector(el);
    this.compileNode(element);
  }

  compileNode(node) {
    node.childNodes.forEach(node => {
      if (node.nodeType === 3) {
        // 文本节点处理
        const reg = /\{\{\s*(\w+)\s*\}\}/;
        if (reg.test(node.nodeValue)) {
          const key = RegExp.$1;
          node.nodeValue = this.$data[key];
          new Watcher(this.$data, key, newVal => {
            node.nodeValue = newVal;
          });
        }
      } else if (node.nodeType === 1) {
        // 元素节点处理
        if (node.hasAttribute('v-model')) {
          const key = node.getAttribute('v-model');
          node.value = this.$data[key];
          new Watcher(this.$data, key, newVal => {
            node.value = newVal;
          });
          node.addEventListener('input', e => {
            this.$data[key] = e.target.value;
          });
        }
      }
    });
  }
}

class Dep {
  constructor() {
    this.subs = [];
  }
  addSub(sub) {
    this.subs.push(sub);
  }
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

class Watcher {
  constructor(data, key, cb) {
    Dep.target = this;
    this.cb = cb;
    this.key = key;
    this.data = data;
    this.value = data[key]; // 触发getter
    Dep.target = null;
  }
  update() {
    this.value = this.data[this.key];
    this.cb(this.value);
  }
}

关键点总结

  • 数据劫持:通过 Object.definePropertyProxy 监听数据变化。
  • 依赖收集:在 getter 中收集依赖(Watcher),在 setter 中触发更新。
  • 模板编译:解析模板中的指令(如 v-model),建立数据与视图的关联。
  • 异步更新:Vue 通过异步队列(nextTick)优化多次数据变更的渲染性能。

标签: 绑定双向
分享给朋友:

相关文章

vue如何实现绑定

vue如何实现绑定

数据绑定基础 Vue 通过 v-bind 指令实现动态绑定 HTML 属性或组件 prop。基本语法为 v-bind:属性名="表达式",简写为 :属性名="表达式"。例如绑定 class 或 sty…

vue怎么实现绑定

vue怎么实现绑定

数据绑定基础 Vue 通过 v-bind 指令实现单向数据绑定(数据从模型到视图),语法为 v-bind:属性="数据" 或简写为 :属性="数据"。例如绑定 src 属性: <img :…

vue实现数据双向

vue实现数据双向

在Vue中实现数据双向绑定主要依靠v-model指令,它结合了属性绑定和事件监听,适用于表单元素或自定义组件。以下是具体实现方式: 基础表单元素的双向绑定 对于原生表单元素(如input、texta…

vue实现数组双向绑定

vue实现数组双向绑定

实现数组双向绑定的方法 在Vue中,实现数组的双向绑定通常需要结合v-model指令或自定义事件处理。以下是几种常见的方法: 使用v-model绑定数组 Vue的v-model指令默认支持表单元素的…

vue怎么实现input绑定

vue怎么实现input绑定

实现 Vue 中 input 绑定的方法 使用 v-model 指令实现双向绑定 v-model 是 Vue 提供的语法糖,用于实现表单元素与数据的双向绑定。它会根据输入框类型自动选取正确的方式更新数…

vue自己实现双向绑定

vue自己实现双向绑定

实现 Vue 双向绑定的核心原理 双向绑定的核心是通过数据劫持结合发布-订阅模式实现的。主要涉及 Object.defineProperty 或 Proxy 来监听数据变化,并通过观察者模式通知视图更…