当前位置:首页 > VUE

vue数据双向绑定实现

2026-01-22 10:26:11VUE

Vue 数据双向绑定的实现原理

Vue 的双向数据绑定主要通过 数据劫持发布-订阅模式 实现,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。以下是具体实现方式:

基于 Object.defineProperty 的实现(Vue 2.x)

数据劫持
通过 Object.defineProperty 劫持对象的属性,在属性被访问或修改时触发 getter 和 setter:

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() {
      console.log(`读取 ${key}: ${val}`);
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        console.log(`设置 ${key}: ${newVal}`);
        val = newVal;
        // 触发更新(模拟依赖通知)
        dep.notify();
      }
    },
  });
}

依赖收集与发布订阅
每个属性维护一个依赖列表(Dep),在 getter 中收集依赖(Watcher),在 setter 中通知更新:

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

class Watcher {
  constructor(vm, key, callback) {
    this.vm = vm;
    this.key = key;
    this.callback = callback;
    Dep.target = this; // 标记当前 Watcher
    this.value = vm[key]; // 触发 getter 以收集依赖
    Dep.target = null;
  }
  update() {
    this.value = this.vm[this.key];
    this.callback(this.value);
  }
}

实现 Observer
递归遍历对象的所有属性,将其转换为响应式:

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) return;
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
    observe(obj[key]); // 深度劫持
  });
}

基于 Proxy 的实现(Vue 3.x)

Vue 3.x 使用 Proxy 替代 Object.defineProperty,解决了后者无法监听数组变化和动态新增属性的问题:

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key); // 依赖收集
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver);
      trigger(target, key); // 触发更新
      return true;
    },
  });
}

依赖收集与触发
通过全局的 effecttrack/trigger 实现:

let activeEffect;
function effect(fn) {
  activeEffect = fn;
  fn(); // 执行时会触发 getter
  activeEffect = null;
}

const targetMap = new WeakMap();
function track(target, key) {
  if (!activeEffect) return;
  let depsMap = targetMap.get(target);
  if (!depsMap) targetMap.set(target, (depsMap = new Map()));
  let dep = depsMap.get(key);
  if (!dep) depsMap.set(key, (dep = new Set()));
  dep.add(activeEffect);
}

function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(key);
  dep && dep.forEach(effect => effect());
}

双向绑定的实际应用

在 Vue 模板中,v-model 是语法糖,结合了 :value@input

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

自定义组件实现
在组件中实现 v-model 需定义 modelValueupdate:modelValue

export default {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  template: `
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
  `,
};

关键区别与优化

  1. Proxy 的优势

    • 直接监听对象而非属性,支持动态新增属性。
    • 无需递归遍历对象,性能更高。
    • 原生支持数组变化监听。
  2. 性能优化

    • Vue 3.x 的响应式系统通过 ProxyWeakMap 减少内存占用。
    • 依赖收集的粒度更细,避免不必要的更新。
  3. 局限性

    • Object.defineProperty 无法检测到对象属性的添加或删除(需配合 Vue.set/Vue.delete)。
    • Proxy 不兼容 IE11,需 polyfill 支持。

vue数据双向绑定实现

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

相关文章

vue实现绑定herf

vue实现绑定herf

Vue 中实现绑定 href 的方法 在 Vue 中绑定 href 属性可以通过多种方式实现,以下是几种常见的方法: 使用 v-bind 或简写 : 通过 v-bind 或简写 : 动态绑定 hr…

vue 数据绑定实现

vue 数据绑定实现

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

vue实现双向绑定

vue实现双向绑定

Vue 双向绑定的实现原理 Vue 的双向绑定是通过 v-model 指令实现的,其本质是语法糖,结合了 v-bind(属性绑定)和 v-on(事件监听)。以下是具体实现方式: 使用 v-mode…

vue实现双向

vue实现双向

Vue 实现双向绑定的方法 Vue 主要通过 v-model 指令实现双向绑定,适用于表单元素或自定义组件。以下是几种常见实现方式: 表单元素的双向绑定 在表单元素(如 input、textare…

uniapp怎么给标签绑定颜色

uniapp怎么给标签绑定颜色

在 uniapp 中给标签绑定颜色 在 uniapp 中,可以通过动态绑定样式或类名的方式为标签设置颜色。以下是几种常见的方法: 动态绑定内联样式 使用 :style 绑定动态样式对象,直接在标签…

实现vue双向绑定

实现vue双向绑定

Vue 双向绑定的实现原理 Vue 的双向绑定主要通过 v-model 指令实现,其核心是结合数据劫持(Object.defineProperty 或 Proxy)和发布-订阅模式。以下是具体实现机制…