本文最后更新于 2024-10-24,文章内容可能已经过时。
问题背景 {#问题背景}
最近在开发 halo 插件过程中,遇到了一个这样的问题,后台使用的 vue3 框架,其中涉及到了父子组件传值,带着 vue2 的开发习惯,对子组件绑定了后端异步获取的数据,以及相应事件,由子组件来渲染获取到的数据。并处理相应逻辑。父子组件代码如下:
- 父组件
<PasteShareSettingEditingModal v-model:isUpdateStatus="isUpdateMode" @update:pasteShare="querySaveRecord"
v-model:visible="settingModal" :pasteShareContent="formState" @close="settingModalClose" />
- 子组件
// 接收父组件传递过来的数据
const props = withDefaults(
defineProps<{
visible: boolean;
isUpdateStatus: boolean;
pasteShareContent?: PasteShareContent;
}>(),
{
visible: false,
isUpdateStatus: false,
pasteShareContent: undefined,
}
);
// 定义子组件触发的事件,通知父组件修改相应的数据
const emit = defineEmits<{
(event: "update:visible", value: boolean): void;
(event: "update:pasteShare", value: object): void;
(event: "close", value: boolean): void;
}>();
上边的代码看着没问题,但是在实际使用中出现了问题:父组件通过 props 传递给子组件的数据更新时,子组件无法及时更新数据并渲染视图。
问题分析 {#问题分析}
只使用 defineProps 来接收父组件传递的数据是不够的,子组件在其一系列生命周期中是不能获取到数据的,父子组件的生命周期流程如下:
父组件 onBeforeMount ---> 子组件 onBeforeMount ---> 子组件 onMounted ---> 父组件 onMounted
如果一开始在父组件的 onBeforeMount中获取数据时,子组件此时还未挂载,是无法获取到数据的,
解决方案 {#解决方案}
1、使用 v-if 控制子组件的挂载时机 {#1-使用-v-if-控制子组件的挂载时机}
<CodeEditor v-if="flag" v-model="codeShare.content" ></CodeEditor>
const initCodeEditor = () => {
console.log('父组件created')
getOasteShareById(props.pasteShareId).then(res => {
flag.value = true //获取到数据改变flag
console.log('父组件获取到数据')
})
}
initCodeEditor();
2、使用计算或侦听方法来处理接收的数据 {#2-使用计算或侦听方法来处理接收的数据}
// 比如使用监听父组件传递的 isUpdateStatus
watch(
() => props.isUpdateStatus,
(val) => {
if (val && !formState.value.spec?.title && !currentPasteShare.value) {
if ("title" in formState.value.spec) {
formState.value.spec.title = "未命名代码段";
}
handleSavePasteShare().then(() => {
emit("update:pasteShare", { name: formState.value.metadata.name, isFirstPublish: false });
});
}
},
{ immediate: true }
);