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

Vue3 Composition API中v-model传入组件值为空的解决方法

问题解决:Composition API下PageModal组件v-model值为undefined的错误

问题描述

我有一个PageModal组件,在Options API视图中能正常工作,但切换到Composition API视图后,传入组件的v-model属性值变为undefined,触发以下错误:

Cannot set properties of undefined (setting 'ref'); stack=TypeError: Cannot set properties of undefined (setting 'ref')

错误触发于PageModal组件的这段代码:

onMounted(() => {
  activeModal.value.ref = activeModalRef.value;
});

我的Composition API视图代码片段:

<template>
  <div>
    <PageModal v-model="activeModal" />
  </div>
</template>

<script>
import PageModal from '@/components/PageModal.vue';

export default {
  name: "MyCustomComponent",
  props: {
    modelValue: {
      type: Object,
      default: () => null
    }
  },
  components: { PageModal },
  emits: ['update:modelValue'],
  setup(props) {
    const activeModal = computed({
      iconName: 'exclamation-triangle-fill',
      hasCancelBtn: false,
      okBtnCallback: () => startOver(),
      title: 'Operation failed.',
      bodyMsg: 'Operation failed. Please try again.'
    });
    ...
    return { activeModal };
  }
};
</script>

而Options API下正常工作的代码是把activeModal放在data中:

data() {
  return {
    activeModal: {
      iconName: 'exclamation-triangle-fill',
      hasCancelBtn: false,
      okBtnCallback: () => startOver(),
      title: 'Operation failed.',
      bodyMsg: 'Operation failed. Please try again.'
    }
  };
}

错误原因

核心问题有两个:

  1. computed用法错误:computed()的参数必须是getter函数(或包含get/set的配置对象),但你直接传入了普通对象,导致activeModal不是有效响应式对象,最终值为undefined,传到子组件后触发赋值错误。
  2. 状态逻辑混淆:代码中定义了modelValueprop却未实际使用,和本地activeModal状态的逻辑冲突,加剧了响应式异常。

解决方案

根据使用场景分两种处理方式:

场景1:activeModal是组件本地状态(不接收父组件v-model)

直接用reactive或ref创建响应式对象,替代错误的computed写法:

<template>
  <div>
    <PageModal v-model="activeModal" />
  </div>
</template>

<script>
import { reactive } from 'vue';
import PageModal from '@/components/PageModal.vue';

export default {
  name: "MyCustomComponent",
  components: { PageModal },
  setup() {
    // 用reactive创建响应式对象,和Options API的data行为一致
    const activeModal = reactive({
      iconName: 'exclamation-triangle-fill',
      hasCancelBtn: false,
      okBtnCallback: () => startOver(),
      title: 'Operation failed.',
      bodyMsg: 'Operation failed. Please try again.'
    });

    // 也可以用ref实现(对象类型的ref同样保持响应式)
    // const activeModal = ref({
    //   iconName: 'exclamation-triangle-fill',
    //   ...
    // });

    ...
    return { activeModal };
  }
};
</script>

场景2:activeModal需要接收父组件的v-model(使用modelValue prop)

如果要通过v-model接收父组件状态,需正确处理modelValue的响应式和更新逻辑:

<template>
  <div>
    <PageModal v-model="localActiveModal" />
  </div>
</template>

<script>
import { computed } from 'vue';
import PageModal from '@/components/PageModal.vue';

export default {
  name: "MyCustomComponent",
  props: {
    modelValue: {
      type: Object,
      default: () => ({
        iconName: 'exclamation-triangle-fill',
        hasCancelBtn: false,
        title: 'Operation failed.',
        bodyMsg: 'Operation failed. Please try again.'
      })
    }
  },
  components: { PageModal },
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    // 用computed包装modelValue,支持双向绑定
    const localActiveModal = computed({
      get() {
        return props.modelValue;
      },
      set(newValue) {
        emit('update:modelValue', newValue);
      }
    });

    // 兜底处理初始值,确保不为undefined
    if (!localActiveModal.value) {
      localActiveModal.value = {
        iconName: 'exclamation-triangle-fill',
        hasCancelBtn: false,
        okBtnCallback: () => startOver(),
        title: 'Operation failed.',
        bodyMsg: 'Operation failed. Please try again.'
      };
    }

    ...
    return { localActiveModal };
  }
};
</script>

关键注意点

  • 传给PageModal的v-model必须绑定已初始化的响应式对象,不能是undefined或null,否则子组件无法给对象的ref属性赋值。
  • 区分响应式API的用法:computed用于基于其他响应式数据计算值,reactive/ref用于创建基础响应式状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:25:37