本文已参与「新人创作礼」活动,一起开启掘金创作之路。
需求简介
使用vue开发的过程中,父子组件之间除了通信之外,偶尔还需要相互调用彼此的方法。比如有时需要通知子组件更新数据或者执行某种操作,就需要调用子组件的方法。
vue2
在vue2中比较简单,假设我们有以下的子组件:
<template>
<div> son </div>
</template>
<script>
export default {
name: 'son',
methods: {
say {
console.log('I am son')
}
}
}
</script>
再创建使用了子组件的父组件:
<template>
<Son ref="son" />
</template>
<script>
import Son from './son.vue'
export deafult {
name: 'father',
components: { Son }
mounted () {
this.$ref.son && this.$ref.son.say()
}
}
</script>
运行后可以看到浏览器控制台打印出
证明调用成功,但在vue3却无法这样做。
vue3
同样,先创建一个子组件:
<template>
<div> son </div>
</template>
<script lang='ts' setup>
function say(): void {
console.log('I am son');
}
</script>
然后在创建一个使用子组件的父组件:
<template>
<Son ref="son" />
</template>
<script lang='ts' setup>
import type { ComponentPublicInstance } from 'vue'
import Son from './son.vue
import { onMounted, ref } from 'vue
const son = ref<ComponentPublicInstance>()
onMounted((): void => {
son.value && son.value.say()
})
</script>
此卢浏览器控制台会报错,提示TypeError: son.value.say is not a function
在 vue3中,如果需要调用子组件的方法,需要先在子组件中将对应的方法暴露出来, 子组件添加后代码如下:
<template>
<div> son </div>
</template>
<script lang='ts' setup>
import { defineExpose } from 'vue'
function say(): void {
console.log('I am son');
}
defineExpose({ say })
</script>
之后才可以在父组件中调用,运行后可以看到浏览器控制台打印出:
但是在使用typeScript的情况下,编辑器会提示
类型“ComponentPublicInstance”上不存在属性“say”,这是因为从vue中导出的类型ComponentPublicInstance上并没有我们加上的say声明,需要定义一个继承自ComponentPublicInstance的类型,同时扩展我们暴露出来的属性和函数:
export interface myType extends ComponentPublicInstance {
computeNewPosition: () => {}
}
然后修改父组件中的类型:
<template>
<Son ref="son" />
</template>
<script lang='ts' setup>
import type { myType } from './type.ts'
import Son from './son.vue
import { onMounted, ref } from 'vue
const son = ref<myType>()
onMounted((): void => {
son.value && son.value.say()
})
</script>
这样编辑器就不会继续提示找不到相应的属性或者方法了。