当前位置:首页 > VUE

vue实现数据劫持

2026-01-18 09:46:50VUE

Vue 数据劫持的实现原理

Vue 的数据劫持主要通过 Object.definePropertyProxy 实现,用于监听数据变化并触发视图更新。

使用 Object.defineProperty

Object.defineProperty 是 Vue 2.x 的核心实现方式,通过劫持对象的属性实现响应式。

vue实现数据劫持

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      console.log(`获取属性 ${key}: ${val}`);
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      console.log(`设置属性 ${key} 从 ${val} 到 ${newVal}`);
      val = newVal;
    }
  });
}

const data = { name: 'Vue' };
defineReactive(data, 'name', data.name);
data.name; // 输出: "获取属性 name: Vue"
data.name = 'React'; // 输出: "设置属性 name 从 Vue 到 React"

使用 Proxy

Vue 3.x 改用 Proxy 实现数据劫持,能够直接监听整个对象而非单个属性。

vue实现数据劫持

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      console.log(`获取属性 ${key}: ${target[key]}`);
      return target[key];
    },
    set(target, key, value) {
      if (target[key] === value) return true;
      console.log(`设置属性 ${key} 从 ${target[key]} 到 ${value}`);
      target[key] = value;
      return true;
    }
  });
}

const data = reactive({ name: 'Vue' });
data.name; // 输出: "获取属性 name: Vue"
data.name = 'React'; // 输出: "设置属性 name 从 Vue 到 React"

深度监听

对于嵌套对象,需递归劫持所有层级的属性。

Object.defineProperty 实现

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) return;
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
    observe(obj[key]); // 递归劫持嵌套属性
  });
}

const data = { user: { name: 'Alice' } };
observe(data);
data.user.name = 'Bob'; // 触发 setter

Proxy 实现

function deepReactive(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;
  Object.keys(obj).forEach(key => {
    obj[key] = deepReactive(obj[key]); // 递归处理嵌套属性
  });
  return reactive(obj);
}

const data = deepReactive({ user: { name: 'Alice' } });
data.user.name = 'Bob'; // 触发 setter

数组的劫持

Vue 2.x 中需特殊处理数组方法(如 pushpop)。

const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift'].forEach(method => {
  const original = arrayProto[method];
  arrayMethods[method] = function(...args) {
    console.log(`数组方法 ${method} 被调用`);
    return original.apply(this, args);
  };
});

function observeArray(arr) {
  arr.__proto__ = arrayMethods;
  arr.forEach(item => observe(item));
}

const list = [1, 2, 3];
observeArray(list);
list.push(4); // 输出: "数组方法 push 被调用"

注意事项

  • Object.defineProperty 无法检测新增或删除的属性,需使用 Vue.setVue.delete
  • Proxy 能直接监听新增/删除属性,但需注意浏览器兼容性(IE 不支持)。
  • 性能上 Proxy 优于递归 defineProperty,尤其对复杂对象结构。

标签: 数据vue
分享给朋友:

相关文章

vue实现tab标签

vue实现tab标签

Vue 实现 Tab 标签的方法 使用动态组件和 v-for 渲染标签 通过 v-for 循环生成标签页标题,结合 v-bind:class 动态切换激活状态。使用 v-show 或动态组件 <…

vue实现多选联动

vue实现多选联动

vue实现多选联动的方法 使用v-model绑定数组 在Vue中,可以通过v-model绑定一个数组来实现多选联动。当复选框被选中或取消选中时,数组会自动更新。 <template>…

vue实现放大效果

vue实现放大效果

使用 CSS transform 实现放大效果 在 Vue 中实现放大效果可以通过 CSS 的 transform: scale() 属性。这种方法简单高效,适合大多数交互场景。 定义一个 CSS…

vue播放倍速怎么实现

vue播放倍速怎么实现

实现Vue播放倍速的方法 在Vue中实现播放倍速功能通常涉及HTML5的<video>元素或第三方播放器库。以下是几种常见实现方式: 使用原生HTML5 video元素 通过ref获取…

vue实现列表显示

vue实现列表显示

Vue 实现列表显示的方法 在 Vue 中实现列表显示通常使用 v-for 指令,结合数组或对象数据渲染动态列表。以下是几种常见的实现方式。 基本列表渲染 通过 v-for 指令遍历数组,动态生成…

vue实现展开与收起

vue实现展开与收起

Vue 实现展开与收起功能 在 Vue 中实现展开与收起功能可以通过多种方式完成,以下是一些常见的方法: 使用 v-show 或 v-if 控制显示 通过 Vue 的指令 v-show 或 v-i…