You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3中如何保留Props初始值?表单组件状态追踪需求

Vue3中存储未知结构Props初始值的最佳实践

针对你开发可复用表单组件时需要存储Props初始值做变更对比的场景,以下是具体方案和分析:

关于toRaw()的适用性:你的用法是安全的

Vue文档不建议持久持有toRaw()获取的原对象,核心原因是原对象可能被外部(比如父组件)修改,导致你持有的值意外变化。但你当前的写法是structuredClone(toRaw(props.modelValue))——你并没有持有原对象本身,而是立刻对原对象做了深克隆,得到了一个完全独立的副本。这个副本和原对象彻底断开了引用关系,后续原对象的任何修改都不会影响它,完全符合存储初始值的需求,所以这个用法是安全的,不需要担心文档的警告。

推荐方案:toRaw() + structuredClone()组合

这个组合是当前场景下最优的选择,理由如下:

  • toRaw()能精准去除Vue3对Props对象添加的Proxy包装,拿到原始的纯JS对象,避免克隆过程中把响应式代理也复制进去
  • structuredClone()原生支持深克隆,能处理几乎所有JS数据类型(包括循环引用、Date、Map、Set等),比JSON序列化方法更可靠,也不需要额外引入第三方库

具体实现代码:

import { toRaw, ref, watch } from 'vue';
import _ from 'lodash'; // 可选,用于深度对比

export default {
  props: {
    modelValue: {
      type: Object,
      required: true
    }
  },
  setup(props) {
    // 存储初始值的副本
    const originalFormValue = ref(null);

    // 初始化+监听父组件更新modelValue时同步更新初始值
    watch(() => props.modelValue, (newVal) => {
      // 先取原对象,再深克隆
      originalFormValue.value = structuredClone(toRaw(newVal));
    }, { immediate: true, deep: true });

    // 判断表单是否变更的方法
    const isFormChanged = () => {
      // 对比时取当前值的原对象,避免Proxy干扰
      const currentRawValue = toRaw(props.modelValue);
      // 用深度对比方法判断是否一致
      return !_.isEqual(currentRawValue, originalFormValue.value);
    };

    return { isFormChanged };
  }
};

替代方案:无toRaw()的实现(可选)

如果你对toRaw()有顾虑,也可以直接对props.modelValue使用structuredClone()——因为structuredClone()会自动忽略Proxy的代理层,直接序列化原始数据。不过这种写法在某些复杂嵌套响应式对象场景下可能存在潜在风险,所以更推荐搭配toRaw()使用。

避坑提示

  • 不要直接存储props.modelValue本身:它是响应式的Proxy对象,后续表单修改会直接改变这个值,无法保留初始状态
  • 不要用JSON序列化:遇到循环引用、Date、Map等类型时会失败或丢失数据
  • 如果父组件会动态更新modelValue,一定要用watch监听并同步更新初始值副本,否则初始值会和最新传入的值不一致

内容的提问来源于stack exchange,提问作者Norah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:43:35