父组件弹窗调用子组件时,无法通过ref、provide、inject等方法调用子组件的方法
问题:
父组件弹窗调用子组件时,无法通过ref、provide、inject等方法调用子组件的方法
场景:
<!-- 新增/编辑弹窗 -->
<el-dialog style="width: auto;" v-model="dataSourceVisible" :title="$t(isEdit ? 'dataSource.editDataSource' : 'dataSource.addDataSource')" @close="handleClose"><component :is="DataSource" ref="dataSourceRef" :OBJECT_GUID="OBJECT_GUID" :PARENT_PATH="PARENT_PATH" @close="handleClose" :showPerformance="showPerformanceList" />
</el-dialog>
需求是在点击弹窗右上角的关闭按钮时,需要清空组件里面的表单验证。但是无法通过ref、provide、inject等方法调用子组件的方法。
失败分析:
父组件无法通过ref等方式调用子组件的方法,主要原因包括子组件尚未创建完成、子组件方法未声明、父组件调用时机不正确等。弹窗里面的子组件内容确实是动态渲染的组件,有可能即使父组件弹窗出来了,弹窗内容还没渲染出来,从而导致父子组件无法通信。
解决方法:
方法1:
子组件对外暴露方法clearDialogValidate,父组件通过ref调用子组件clearDialogValidate方法(不推荐)
defineExpose({clearDialogValidate
});
不是说不能通过ref调用子组件实例吗?但是,
使用 v-if
来控制子组件的渲染,确保在调用方法时子组件已经挂载;然后使用 nextTick
或 setTimeout
来延迟调用子组件的方法,确保子组件已经挂载。
<!-- 新增/编辑弹窗 -->
<el-dialog style="width: auto;" v-model="dataSourceVisible" :title="$t(isEdit ? 'dataSource.editDataSource' : 'dataSource.addDataSource')" @close="handleClose"><component :is="DataSource" v-if="dataSourceVisible" v-model="dataSourceVisible" ref="dataSourceRef" :OBJECT_GUID="OBJECT_GUID" :PARENT_PATH="PARENT_PATH" @close="handleClose" :showPerformance="showPerformanceList" />
</el-dialog>
const dataSourceRef = ref(null);
// 关闭新增/编辑数据弹窗
const handleClose = () => {setTimeout(() => {if (dataSourceRef?.value?.componentRef?.value &&typeof dataSourceRef.value.componentRef.value.clearDialogValidate === 'function') {dataSourceRef.value.componentRef.value.clearDialogValidate();}}, 0); // 延迟 100ms 或 0 ms都可以,给子组件足够的时间挂载OBJECT_GUID.value = '';requestDataSource();showPerformanceList.value = false;dataSourceVisible.value = false;
}
这样就可以点击右上角关闭按钮时调用子组件的clearDialogValidate去清空校验了。但是会使组件内的clearValidate方法报错。所以行不通。
// 清空表单校验
const clearDialogValidate = () => {setTimeout(() => {proxy.$refs["dataSourceRuleForm"].clearValidate();}, 0);
};
方法2:
父组件弹窗关闭时销毁子组件(调用官方API:destroy-on-close),然后子组件在挂载成功时,清空一下表单校验即可。
在el-dialog里写上destroy-on-close (在关闭弹窗时销毁子组件内容)
<!-- 新增/编辑数据链接弹窗 -->
<el-dialog style="width: auto;" v-model="dataSourceVisible" :title="$t(isEdit ? 'dataSource.editDataSource' : 'dataSource.addDataSource')" @close="handleClose" destroy-on-close><component :is="DataSource" :OBJECT_GUID="OBJECT_GUID" :PARENT_PATH="PARENT_PATH" @close="handleClose" :showPerformance="showPerformanceList" />
</el-dialog>
子组件:
在子组件onMounted挂载时调用clearDialogValidate();清空一下校验即可。
onMounted(() => {showPerformanceList.value = props.showPerformance......clearDialogValidate();
});
// 清空表单校验
const clearDialogValidate = () => {setTimeout(() => {proxy.$refs["dataSourceRuleForm"].clearValidate();}, 0);
};
总结:
方法2简单有效。