当前位置:首页 > VUE

vue数据拦截怎么实现

2026-01-23 12:36:23VUE

Vue 数据拦截的实现方式

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

vue数据拦截怎么实现

使用 Object.defineProperty(Vue 2.x)

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

vue数据拦截怎么实现

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"

实现依赖收集与更新

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

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 的“查看更多”功能 数据截取与显示控制 通过 v-if 或 v-show 控制内容的显示与隐藏。初始状态下只显示部分内容,点击“查看更多”后展开完整内容。 <template&…

vue实现无线滚动列表

vue实现无线滚动列表

无限滚动列表的实现方法 在Vue中实现无限滚动列表通常结合监听滚动事件和动态加载数据。以下是几种常见方法: 使用自定义指令 创建自定义指令v-infinite-scroll监听滚动事件: Vu…

vue实现录音文件播放

vue实现录音文件播放

使用 Vue 实现录音文件播放 准备工作 确保项目中已安装必要的依赖,如 vue-audio-recorder 或原生 Web Audio API。录音文件播放通常涉及录音、存储和播放三个核心环节。…

vue里实现增删改查

vue里实现增删改查

在Vue中实现增删改查 数据初始化 在Vue组件的data中定义初始数据和表单绑定的变量: data() { return { items: [ { id: 1, name…

vue实现密码框的包

vue实现密码框的包

Vue 密码框实现方案 在 Vue 中实现密码框功能,可以通过原生 HTML 结合 Vue 指令或使用第三方组件库完成。以下是几种常见方案: 原生 HTML + Vue 双向绑定 <temp…

vue实现钟表

vue实现钟表

使用 Vue 实现动态钟表 以下是一个基于 Vue 3 的动态钟表实现方案,包含时分秒指针和数字时间显示。 模板部分 <template> <div class="clock…