如何使用TypeScript在Vue3中定义ref(绑定在模板上)的类型



模板:

<tremplate>
<div ref="element"></div>
</template>

脚本:

export default {
setup() {
const element = ref(null);
return {
element,
};
},
};

这是在vue3中定义ref的正常方式,但使用JavaScript方式。如果我使用TypeScript,我将需要为值element定义一个类型,对吗?

如何确保值element的类型正确?

好吧,这将取决于您是否需要键入它并提供成员信息(公共属性、方法等(。如果你这样做了,那么是的,你需要为它定义一个类型;否则,您不必这样做,并且可以简单地使用.value访问展开的引用,从而将其保留为类型any(我敢打赌您已经找到了这个(。

但是,如果必须这样做,您需要告诉编译器它是什么,或者它将被分配给什么。为此,您需要使用ref的第三个重载(没有参数(,并将泛型类型显式设置为所需类型——在您的情况下,您需要HTMLDivElement(如果您不关心它必须提供的特定成员,则只需要HTMLElement(。

export default defineComponent({
setup() {
const el = ref<HTMLDivElement>();
onMounted(() => {
el.value // DIV element
});
return {
el
}
}
})

在JavaScript中,您没有类型检查,所以在ref函数上传递null和不传递任何内容一样好(这对模板引用来说尤其好(*;从某种意义上说,它甚至可能被认为是误导性的,即展开的值实际上解析为其他null

*当使用组合物API时;反应性参考文献";以及";模板引用";是统一的。我们之所以在挂载的钩子上访问这种特定类型的ref,是因为DOM元素将在初始渲染后分配给它。

参考文献:

  • https://v3.vuejs.org/guide/composition-api-template-refs.html#template-参考文献
<template>
<ChildComponent ref="childRef">
</template>
<script lang="ts" setup>
import ChildComponent from './ChildComponent.vue'
import { ref } from 'vue'
const childRef = ref<InstanceType<typeof ChildComponent>>()
childRef.value.childMethods()
</script>

行不正确:

const el = ref<HTMLDivElement>();

el不是HTMLDivElement。相反,它是元素的代理。该代理的$el是实际的HTMLDivElement。虽然我不确定我是否做对了。在一个组件中,我设法将其键入如下:

import { ComponentPublicInstance, defineComponent, ref } from 'vue';
export default defineComponent({
// snipped...
setup() {
const field = ref<ComponentPublicInstance<HTMLInputElement>>();
return {
field,
fun() { field.value.$el.value = 'some value'; }
};
}
// snipped...
});

Vue 3成分API

<template>
<input ref="fileInput" style="display: none;" type="file" @change="onFileSelected" />
<button @click="fileInput?.click()">Pick Files</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const fileInput = ref<HTMLDivElement | null>(null)
function onFileSelected(event: any) { console.log("Event: " + event) }
</script>

第二个例子

<template>
<div ref="coolDiv">Some text</div>
<button @click="changeCoolDiv">Pick Files</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const coolDiv = ref<HTMLDivElement>()
function changeCoolDiv() {
if(coolDiv) {
coolDiv.value // Div element
}
}
</script>

来自Vue 3文档:

默认情况下,使用<script setup>的组件是关闭的,即通过模板引用或$parent链检索的组件的公共实例将不会公开内部声明的任何绑定。

要显式公开组件中的属性,请使用defineExpose编译器宏:

<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>

当父级通过模板引用获得该组件的实例时,检索到的实例的形状将为{ a: number, b: number }(引用会像普通实例一样自动展开(。

示例代码

从文档:

组件MyModal.vue:

<script setup lang="ts">
import { ref } from 'vue'
const isContentShown = ref(false)
const open = () => (isContentShown.value = true)
defineExpose({
open
})
</script>

父组件App.vue:

<script setup lang="ts">
import MyModal from './MyModal.vue'
const modal = ref<InstanceType<typeof MyModal> | null>(null)
const openModal = () => {
modal.value?.open()
}
</script>
import { VNodeRef } from 'vue';

您可以使用VNodeRef。

const swiperRef = ref<VNodeRef>();

如果使用vue-class-component软件包(此处为beta v8,但与@Component相同,而不是@Option(:

<template>
<div ref="element">
<MyOtherComponent ref="otherComponent" />
</div>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component'
import MyOtherComponent from '../MyOtherComponent.vue'
@Options({
components: {
MyOtherComponent,
},
})
export default class MyComponent extends Vue {
$refs!: {
element: HTMLDivElement,
otherComponent: InstanceType<typeof MyOtherComponent>,
}
mounted() {
this.$refs.otherComponent.myOtherComponentMethod()
}
}
</script>

最新更新