题目中的写法是对的,只不过拿到的引用是空的。
子组件需要明确使用expose
方法暴露出接口之后,才能在父组件获取到接口引用。
未暴露接口的情况下,引用的始终是一个空对象。
// child.vue
<template>
<div>child</div>
</template>
<script setup>
import { useContext } from "vue";
const { expose } = useContext(); // 通过context获取expose方法
const sayHi = ref('Hello world');
expose({
sayHi // 明确的暴露接口
});
</script>
// parent.vue
<template>
<div>I have a child</div>
<Child ref="childRef" />
</template>
<script setup>
import { onMounted } from "vue";
import Child from "./child.vue"
const childRef = ref(null) // 子组件引用
onMounted(()=>{
console.log(childRef.value); // => Proxy {sayHi: RefImpl}
console.log(childRef.value.sayHi); // => Hello world
})
</script>
vue3使用$refs ,可以通过vm = getCurrentInstance()拿到组件实例,然后在 vm.ctx.$refs 上找到对模板的引用。https://feizhaojun.com/?p=3355
在当前项目我使用的解法
<template>
<component :is="componentId" ref="componentRef"></compoent>
</template>
<script lang="ts" setup>
import { defineAsyncComponent, computed } from 'vue'
const asyncFileComponent = defineAsyncComponent(() => import('./file.vue'))
const asyncTableComponent = defineAsyncComponent(() => import('./table.vue'))
const componentRef = ref<InstanceType<typeof asyncFileComponent> | InstanceType<typeof asyncTableComponent> | null>(null)
const type = ref<string>('file')
const componentId = computed(() => {
if (type.value === 'file') return asyncFileComponent
if (type.value === 'table') return asyncTableComponent
else return null
})
const handleClick = () => {
// 此时需要子组件都对外暴露 reload 方法
componentRef.vlaue?.reload()
}
</script>
注意mounted
不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在mounted
内部使用vm.$nextTick
v3也同样有这个提示,生命周期钩子 | Vue.js
5 回答4.8k 阅读✓ 已解决
4 回答3k 阅读✓ 已解决
2 回答4.7k 阅读✓ 已解决
4 回答4.3k 阅读✓ 已解决
3 回答3.2k 阅读✓ 已解决
4 回答1.8k 阅读✓ 已解决
2 回答2.6k 阅读✓ 已解决
感觉跟
defineAsyncComponent
有关系,组件还没加载出来,onMounted
已经执行完了。