当前位置:首页 > 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 异步组件实现原理 Vue 的异步组件允许将组件按需加载,通常用于代码分割或延迟加载非关键组件。其核心原理基于 Promise 和动态导入。 基本实现方式 通过 defineAsyncComp…

vue实现跑车

vue实现跑车

Vue 实现跑车动画效果 使用 Vue 结合 CSS 动画可以实现跑车在屏幕上移动的效果。以下是一个完整的实现方案: 创建 Vue 组件结构 <template> <div c…

vue实现盖章

vue实现盖章

Vue 实现盖章功能 在Vue中实现盖章功能通常涉及前端UI交互,通过Canvas或SVG绘制印章,并允许用户拖拽或点击放置印章。以下是具体实现方法: 使用Canvas绘制印章 通过HTML5的Ca…

vue实现swipe

vue实现swipe

Vue实现Swipe功能的方法 使用第三方库(推荐) Vue生态中有多个成熟的轮播/滑动组件库,例如vue-awesome-swiper或swiper/vue。以下是基于swiper/vue的实现示例…

vue实现表单

vue实现表单

Vue 表单实现方法 双向数据绑定 使用 v-model 指令实现表单元素与数据的双向绑定。适用于 input、textarea、select 等元素。 <template> <…

vue实现翻页

vue实现翻页

Vue实现翻页功能 在Vue中实现翻页功能通常需要结合分页组件和数据请求逻辑。以下是常见的实现方法: 使用Element UI分页组件 安装Element UI后,可以直接使用其分页组件:…