Vue3 + TS项目,获取的子组件实例可能为 null 的问题

1,问题表现

子组件

<script setup>
const count = ref(0)

defineExpose({
  count
})
</script>

获取子组件实例

1,JavaScript 版本

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const child = ref(null)
const onClick = () => {
  // child.value 是 <Child /> 组件的实例
  console.log(child.value.count)
}
</script>

<template>
  <Child ref="child" />
  <button @click="onClick">点击试下</button>
</template>

虽然默认值是 null,但通过点击事件触发时,child 早已被赋值,所以直接写 child.value.count 是没有问题的。

2,但在 typescript 版本中,会报错

<script setup lang="ts">
import { ref } from 'vue'
import Child from './Child.vue'

// 标注类型 
const child= ref<InstanceType<typeof Child > | null>(null)

const onClick = () => {
  // 报错,'child.value' is possibly 'null'.ts(18047)
  console.log(child.value.count)
}
</script>

<template>
  <Child ref="child" />
  <button @click="onClick">点击试下</button>
</template>

参考:Vue 官方文档,为子组件标注类型

2,解决问题

2.1,使用非空判断

const onClick = () => {
  console.log(child.value?.count)
}

2.2,使用非空断言

什么是非空断言

const onClick = () => {
  console.log(child.value!.count)
}

2.3,使用类型断言

什么是类型断言

如果不想每次都加 ? ! ,可以在定义子组件实例时进行类型断言:

import type { Ref } from "vue";
import Child from './Child.vue'

const child= ref() as Ref<InstanceType<typeof Child>>

2.4,3种方式的区别

断言非空判断的本质是不一样的。

  • 断言是跳过类型检查,后面的代码会被执行。
  • 非空判断,后面的代码不一定会被执行。

所以,使用时得注意:

  1. 断言,只适合使用的子组件实例确定存在时,比如点击事件或 onMounted 生命周期函数中。
  2. 非空判断,适用性比较广,并且子组件实例不确定是否存在时,只能使用非空判断,比如computed 计算属性等场景中。

以上。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue3中使用TypeScript获取动态组件component实例调用里面组件的方法,可以先通过 `ref` 获取动态组件实例,再通过 `as` 关键字将其转换为具体的组件类型,从而调用组件中的方法。 例如,假设有一个动态组件 `MyComponent`,其中包含了一个组件 `ChildComponent`,并且我们需要在父组件获取 `ChildComponent` 实例并调用其方法。可以使用如下代码: ```vue <template> <div> <component :is="selectedComponent" ref="myComponent"></component> <button @click="handleClick">Call Child's Method</button> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue' import ChildComponent from './ChildComponent.vue' export default defineComponent({ components: { ChildComponent }, data() { return { selectedComponent: 'ChildComponent' } }, setup() { const myComponentRef = ref<MyComponent | null>(null) const handleClick = () => { const childComponent = myComponentRef.value?.$refs.child as ChildComponent if (childComponent) { childComponent.doSomething() } } return { myComponentRef, handleClick } } }) </script> ``` 在上面的代码中,我们使用 `ref` 将动态组件 `MyComponent` 的实例绑定到 `myComponentRef` 变量上,并使用 `as` 关键字将其类型转换为 `MyComponent | null`。然后,在 `handleClick` 方法中,我们通过 `myComponentRef.value?.$refs.child` 获取组件 `ChildComponent` 的实例,并将其类型转换为 `ChildComponent`。最后,我们就可以调用 `ChildComponent` 中的方法了。 需要注意的是,在模板中使用 `ref` 时,需要添加一个 `.value` 后缀来访问 `ref` 变量所引用的对象。例如,上面的代码中,我们通过 `myComponentRef.value?.$refs.child` 来获取组件 `ChildComponent` 的实例。 另外,如果组件中的方法需要访问组件的数据或者方法,可以使用 `provide` 和 `inject` 方法来实现。具体使用方法可以参考 Vue3 官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下雪天的夏风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值