在Vue2时我们想获取DOM元素或者组件节点时一般使用this.$refs.xxx。现在在Vue3时代,需要稍微改变一点点方法 ,但是还依然使用ref来获取。
<template>
<!-- 一个dom元素节点 -->
<div ref="domRef">这是一个DOM元素</div>
<!-- 一个子组件 -->
<child ref="childRef"></child>
</template>
下面是实现逻辑:
import { defineComponent, onMounted, ref } from 'vue'
import Child from '@components/child.vue'
export default defineComponent({
components: {
Child
},
setup() {
// 定义元素的节点类型
const domRef = ref<HTMLElement>()
// 定义组件的节点类型,使用 InstanceType 配合 typeof 获取子组件的类型
const childRef = ref<InstanceType<typeof Child>>()
// 获取元素或者组件时,需要在视图渲染完毕之后进行
onMounted(() => {
const text = domRef.value.innerText;
// 操作子组件
if (childRef.value) {
childRef.value.visible = true;
}
})
// 使用ref声明的变量必须return出去才能被template正常使用
return {
domRef,
childRef
}
}
})
单纯使用 typeof Child 虽然可以获得 Child.vue 组件的 Props 和方法等提示,但在 VSCode 的类型推导还不够智能,缺乏更有效的代码补全支持。
上文使用的 InstanceType<T> 是 TypeScript 提供的一个工具类型,可以获取构造函数类型的实例类型,因此将组件的类型声明为 InstanceType<typeof Child> ,不仅可以得到更完善的类型提示,在编程过程中还可以让编辑器提供更完善的代码补全功能。
上面代码还有一个细节是对childRef.value增加了一个是否为空的判断,这主要是为了解决TS报错的问题。这是因为一些脚手架创建出来的项目会默认启用 --strictNullChecks 选项,导致可能存在null和undefined类型,所以为了解决这个问题才有了上述方案,不过还有另一种方案是
// 如果仅仅是读取值,则可以使用可选?操作符
const value = childRef.value?.visible;
// 如果是赋值操作,则需要先判断是否为空
if (childRef.value) {
childRef.value.visible = true;
}
在Vue3中,获取DOM元素或组件节点的方式略有变化,仍然使用ref但需配合ref的实例类型。通过`ref<HTMLElement>`定义DOM元素节点,用`ref<InstanceType<typeofChild>>`定义组件节点,以获得更好的类型提示和代码补全。在`onMounted`生命周期钩子中安全地访问这些引用,同时处理可能的null值以避免严格模式下的类型检查错误。
2458

被折叠的 条评论
为什么被折叠?



