Vue watch、computed、toRef、onMounted 解构 props 简单应用场景

props.detailData 是父控件传的值,如何将 detailData 中的 custodyNo 赋值给 formData 中的 reason

父控件
<Detail v-model="detailVisible" :detailData="currentDetailData" />

子控件
const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}), // 默认空对象,避免 undefined
  },
});

const formData = reactive({
  status: 1,
  reason: props.detailData.CustodyNo,
});

在 Vue 3 中,你可以使用 watch 来监听 props.detailData 的变化,并在变化时将 custodyNo 赋值给 formData.reason。以下是实现方式:

import { reactive, watch } from 'vue';

const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}), // 默认空对象,避免 undefined
  },
});

const formData = reactive({
  status: 1,
  reason: props.detailData.custodyNo || '', // 初始赋值
});

// 监听 props.detailData 的变化
watch(
  () => props.detailData,
  (newDetailData) => {
    formData.reason = newDetailData.custodyNo || '';
  },
  { deep: true, immediate: true } // deep: 深度监听对象变化,immediate: 立即执行一次
);

注意事项:

  1. 我注意到你在代码中使用了 CustodyNo(大写开头),但在问题描述中写的是 custodyNo(小写开头)。请确保属性名大小写一致。
  2. watchdeep: true 选项确保能监听到对象内部属性的变化。
  3. immediate: true 选项会在组件创建时立即执行一次回调,确保初始值被正确设置。
  4. 添加了 || '' 作为后备值,避免在 custodyNo 为 undefined 时出现问题。

如果你的属性名确实是 CustodyNo(大写开头),则应该修改为:

formData.reason = newDetailData.CustodyNo || '';

除了使用 watch,还有以下几种方法可以将 props.detailData.custodyNo 赋值给 formData.reason


方法 1:使用 toRefcomputed(推荐)

如果 formData.reason 需要始终同步 props.detailData.custodyNo,可以使用 computedtoRef(适用于 Vue 3.2+)。

(1)使用 computed

import { reactive, computed } from 'vue';

const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}),
  },
});

const formData = reactive({
  status: 1,
  reason: computed(() => props.detailData.custodyNo || ''), // 自动同步
});

特点

  • formData.reason 会随 props.detailData.custodyNo 自动更新。
  • formData.reason 会变成 readonly,不能直接修改(除非结合 setter)。

(2)使用 toRef(Vue 3.2+)

import { reactive, toRef } from 'vue';

const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}),
  },
});

const formData = reactive({
  status: 1,
  reason: toRef(props.detailData, 'custodyNo'), // 直接引用
});

特点

  • formData.reason 直接引用 props.detailData.custodyNo,修改 reason 会影响 detailData(除非 detailData 是只读的)。
  • 适用于需要双向绑定的情况。

方法 2:在 onMountedsetup 中初始化

如果 detailData 只初始化一次(不会动态变化),可以直接在 setuponMounted 里赋值:

import { reactive, onMounted } from 'vue';

const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}),
  },
});

const formData = reactive({
  status: 1,
  reason: props.detailData.custodyNo || '', // 初始化
});

// 如果父组件可能异步传值,可以在 onMounted 里再检查一次
onMounted(() => {
  if (props.detailData.custodyNo) {
    formData.reason = props.detailData.custodyNo;
  }
});

特点

  • 适用于 detailData 不会动态变化的情况。
  • 如果父组件是异步加载数据,可能需要结合 watchonUpdated 监听变化。

方法 3:使用 v-model + 计算属性(双向绑定)

如果希望 formData.reason 既能接收 props.detailData.custodyNo,又能修改并通知父组件,可以使用 v-model + computedget/set

import { computed } from 'vue';

const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}),
  },
});

const emit = defineEmits(['update:detailData']);

const formData = reactive({
  status: 1,
  reason: computed({
    get: () => props.detailData.custodyNo || '',
    set: (value) => {
      emit('update:detailData', { ...props.detailData, custodyNo: value });
    },
  }),
});

特点

  • 适用于需要双向绑定的情况(子组件修改 reason 能同步到父组件)。
  • 父组件需要用 v-model:detailData.sync 方式传值。

方法 4:直接解构 props(适用于简单场景)

如果 formData 只需要 detailData 的某些字段,可以解构 props

const props = defineProps({
  detailData: {
    type: Object,
    default: () => ({}),
  },
});

const formData = reactive({
  status: 1,
  ...pick(props.detailData, ['custodyNo']), // 直接解构
});

特点

  • 适用于 formDatadetailData 结构相似的情况。
  • 但无法自动更新(除非结合 watchcomputed)。

总结

方法 适用场景 是否自动更新 是否可修改
watch 监听变化
computed 只读依赖 ❌(除非用 setter
toRef 直接引用 ✅(可能影响父组件)
onMounted 初始化赋值
v-model + computed 双向绑定
解构 props 简单映射

推荐

  • 如果只是 单向同步(子组件只读),用 computed
  • 如果需要 双向绑定,用 v-model + computedget/set
  • 如果 detailData 不会变化,直接用 onMountedsetup 初始化。
posted @ 2025-08-19 13:31  VipSoft  阅读(29)  评论(0)    收藏  举报