当前位置:首页 > VUE

vue如何实现响应式

2026-02-23 09:16:17VUE

Vue 响应式原理

Vue 的响应式系统通过数据劫持和依赖收集实现,核心是使用 Object.defineProperty(Vue 2)或 Proxy(Vue 3)来监听数据变化。

数据劫持

在 Vue 2 中,通过 Object.defineProperty 递归地将对象的属性转换为 getter/setter,当数据被访问或修改时触发相应的钩子函数。

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() {
      console.log(`访问 ${key}`);
      return val;
    },
    set(newVal) {
      console.log(`修改 ${key} 为 ${newVal}`);
      val = newVal;
    }
  });
}

在 Vue 3 中,改用 Proxy 实现数据劫持,可以监听整个对象而无需递归遍历属性。

const reactive = (target) => {
  return new Proxy(target, {
    get(target, key) {
      console.log(`访问 ${key}`);
      return target[key];
    },
    set(target, key, value) {
      console.log(`修改 ${key} 为 ${value}`);
      target[key] = value;
      return true;
    }
  });
};

依赖收集

Vue 通过依赖收集跟踪数据的依赖关系。每个响应式属性都有一个对应的 Dep 实例,用于存储依赖(Watcher)。当数据被访问时,当前 Watcher 会被添加到 Dep 中;当数据被修改时,Dep 会通知所有 Watcher 更新。

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

实现 Watcher

Watcher 是数据和视图之间的桥梁,负责在数据变化时更新视图。

let target = null;

class Watcher {
  constructor(vm, exp, fn) {
    this.vm = vm;
    this.exp = exp;
    this.fn = fn;
    target = this;
    this.vm[this.exp]; // 触发 getter 收集依赖
    target = null;
  }
  update() {
    this.fn.call(this.vm, this.vm[this.exp]);
  }
}

响应式数据示例

结合以上概念,可以创建一个简单的响应式系统:

function observe(data) {
  Object.keys(data).forEach(key => {
    let value = data[key];
    const dep = new Dep();

    Object.defineProperty(data, key, {
      get() {
        dep.depend();
        return value;
      },
      set(newVal) {
        if (newVal === value) return;
        value = newVal;
        dep.notify();
      }
    });
  });
}

const vm = { count: 0 };
observe(vm);

new Watcher(vm, 'count', (val) => {
  console.log(`count 更新为 ${val}`);
});

vm.count++; // 输出 "count 更新为 1"

数组响应式处理

Vue 对数组方法(如 pushpop)进行了特殊处理,通过重写这些方法实现响应式。

const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);

['push', 'pop', 'shift', 'unshift'].forEach(method => {
  const original = arrayProto[method];
  arrayMethods[method] = function(...args) {
    const result = original.apply(this, args);
    this.__ob__.dep.notify(); // 通知更新
    return result;
  };
});

Vue 3 的改进

Vue 3 使用 Proxy 替代 Object.defineProperty,解决了以下问题:

vue如何实现响应式

  • 无需递归遍历对象属性。
  • 可以监听新增或删除的属性。
  • 对数组的支持更自然,无需重写方法。
const reactive = (target) => {
  const handler = {
    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;
    }
  };
  return new Proxy(target, handler);
};

总结

Vue 的响应式系统通过数据劫持和依赖收集实现数据的自动更新。Vue 2 使用 Object.defineProperty,Vue 3 改用 Proxy,提高了性能和灵活性。理解这些原理有助于更好地使用 Vue 并解决相关问题。

标签: 如何实现vue
分享给朋友:

相关文章

vue实现简单的弹窗

vue实现简单的弹窗

使用 Vue 实现简单弹窗 组件基础结构 创建一个名为 Modal.vue 的组件文件,包含模板、脚本和样式部分: <template> <div class="mod…

vue实现长按

vue实现长按

Vue 实现长按功能的方法 在 Vue 中实现长按功能可以通过原生事件监听或自定义指令完成。以下是几种常见实现方式: 使用原生事件监听 通过 @mousedown 和 @mouseup 或 @tou…

vue翻页实现

vue翻页实现

Vue翻页实现方法 基础分页组件实现 使用v-for和计算属性实现基础分页逻辑: <template> <div> <ul> <li…

vue拖动实现

vue拖动实现

实现 Vue 拖动功能的方法 使用 HTML5 拖放 API 在 Vue 中可以利用 HTML5 的原生拖放 API 实现拖动功能。通过 draggable 属性标记可拖动元素,结合 @dragsta…

vue 实现折叠

vue 实现折叠

Vue 实现折叠功能的方法 在 Vue 中实现折叠功能可以通过多种方式完成,以下是几种常见的实现方法: 使用 v-if 或 v-show 控制显示隐藏 通过绑定一个布尔值变量,结合 v-if 或 v…

vue实现单击

vue实现单击

Vue 实现单击事件的方法 在 Vue 中实现单击事件可以通过 v-on 指令或简写的 @ 符号绑定事件处理器。以下是几种常见的实现方式: 基础用法 通过 v-on:click 或 @click 绑…