当前位置:首页 > VUE

vue数据拦截怎么实现

2026-01-23 12:36:23VUE

Vue 数据拦截的实现方式

Vue 的数据拦截核心是通过 Object.definePropertyProxy 实现的响应式系统,以下是具体实现方法:

使用 Object.defineProperty(Vue 2.x)

通过劫持对象的属性访问和修改,触发依赖收集和更新通知。

function defineReactive(obj, key, val) {
  // 递归处理嵌套对象
  observe(val);

  Object.defineProperty(obj, key, {
    get() {
      console.log(`读取 ${key}: ${val}`);
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        console.log(`设置 ${key} 为 ${newVal}`);
        observe(newVal); // 新值为对象时递归拦截
        val = newVal;
      }
    }
  });
}

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) return;

  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
  });
}

// 测试
const data = { foo: 'bar' };
observe(data);
data.foo; // 输出 "读取 foo: bar"
data.foo = 'baz'; // 输出 "设置 foo 为 baz"

使用 Proxy(Vue 3.x)

通过代理对象拦截所有属性的操作,支持数组和动态新增属性。

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      console.log(`读取 ${key}: ${target[key]}`);
      return target[key];
    },
    set(target, key, val) {
      if (target[key] !== val) {
        console.log(`设置 ${key} 为 ${val}`);
        target[key] = val;
      }
      return true;
    }
  });
}

// 测试
const data = reactive({ foo: 'bar' });
data.foo; // 输出 "读取 foo: bar"
data.foo = 'baz'; // 输出 "设置 foo 为 baz"

实现依赖收集与更新

结合发布-订阅模式,在拦截时触发依赖更新:

vue数据拦截怎么实现

class Dep {
  constructor() {
    this.subscribers = new Set();
  }
  depend() {
    if (activeEffect) this.subscribers.add(activeEffect);
  }
  notify() {
    this.subscribers.forEach(effect => effect());
  }
}

let activeEffect = null;
function watchEffect(effect) {
  activeEffect = effect;
  effect();
  activeEffect = null;
}

// 修改 defineReactive 加入依赖收集
function defineReactive(obj, key, val) {
  const dep = new Dep();
  observe(val);
  Object.defineProperty(obj, key, {
    get() {
      dep.depend();
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        observe(newVal);
        val = newVal;
        dep.notify();
      }
    }
  });
}

// 测试
const data = { count: 0 };
observe(data);
watchEffect(() => {
  console.log(`当前计数: ${data.count}`);
});
data.count++; // 触发日志输出

注意事项

  1. 性能问题Object.defineProperty 需要递归遍历对象,初始化性能较差。
  2. 数组限制:Vue 2.x 需重写数组方法(如 push)实现拦截。
  3. Proxy 优势:Vue 3.x 的 Proxy 直接支持动态属性和数组操作。

通过上述方法可以实现类似 Vue 的响应式数据拦截,核心在于在数据访问时收集依赖,在数据变更时触发更新。

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

相关文章

订单 vue实现

订单 vue实现

Vue 实现订单功能 数据模型设计 订单功能通常需要设计以下数据结构: // 订单数据结构 const order = { id: '', // 订单ID userId:…

vue中如何实现循环

vue中如何实现循环

在 Vue 中实现循环 Vue 提供了 v-for 指令用于实现循环渲染列表数据。v-for 可以遍历数组、对象或数字范围,生成动态的 DOM 元素。 遍历数组 使用 v-for 遍历数组时,语法为…

vue实现分类

vue实现分类

Vue实现分类功能的方法 使用v-for和计算属性 通过计算属性对数据进行分类处理,结合v-for渲染分类后的列表。示例代码: <template> <div>…

vue实现高亮

vue实现高亮

Vue 实现文本高亮的方法 在 Vue 中实现文本高亮可以通过多种方式完成,以下是几种常见的方法: 方法一:使用 v-html 指令 通过 v-html 指令可以动态插入 HTML 内容,将需要高…

vue实现popper

vue实现popper

Vue 实现 Popper 的方法 使用 Tippy.js 库 Tippy.js 是一个轻量级的 Popper.js 封装库,提供丰富的工具提示功能。安装 Tippy.js 及其 Vue 封装: n…

vue实现tabbar

vue实现tabbar

Vue 实现 TabBar 的方法 使用 Vue Router 实现基础 TabBar 安装 Vue Router 依赖: npm install vue-router 创建路由配置文件(route…