当前位置:首页 > 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双向绑定的实现原理 Vue的双向绑定主要通过数据劫持结合发布-订阅模式实现。核心是利用Object.defineProperty()或ES6的Proxy来劫持各个属性的getter和setter…

vue 数据绑定实现

vue 数据绑定实现

Vue 数据绑定的实现方式 Vue 的数据绑定主要通过响应式系统和模板语法实现,以下是核心方法: 双向数据绑定(v-model) 通过 v-model 指令实现表单元素与数据的双向绑定,自动同步数…

vue实现绑定输入参数

vue实现绑定输入参数

Vue 实现绑定输入参数 在 Vue 中,可以通过 v-model 指令实现输入框与数据的双向绑定。以下是一个简单的示例: <template> <div> &l…

vue样式绑定实现收藏

vue样式绑定实现收藏

Vue 样式绑定实现收藏功能 在 Vue 中,可以通过动态绑定样式来实现收藏功能,常见的方法是使用 v-bind:class 或 v-bind:style 来切换样式状态。 使用 v-bind:cl…

vue实现双向绑定的是

vue实现双向绑定的是

Vue 双向绑定实现原理 Vue 实现双向绑定的核心机制是数据劫持结合发布-订阅模式,主要通过 v-model 指令实现。以下是关键实现细节: 数据劫持(响应式系统) Vue 2.x 使用 Obje…

vue实现事件绑定的是

vue实现事件绑定的是

Vue 事件绑定实现方式 Vue 通过 v-on 指令实现事件绑定,语法为 v-on:事件名="处理方法" 或简写为 @事件名="处理方法"。以下是具体实现方法和示例: 基础事件绑定 <…