本章我们来讲解vue3 ts 中 defineProps、defineEmits、defineExpose、defineOptions、defineSlots的使用及作用。
在Vue3中,defineProps、defineEmits、defineExpose、defineOptions、defineSlots是一组新的功能函数,用于定义组件的属性、事件、暴露、选项和插槽。
defineProps:用于定义组件的属性。通过调用该函数,可以声明组件的属性,并且将属性的类型、默认值等信息进行声明。这样,可以在组件内部通过props属性来接收父组件传递的属性值。
defineEmits:用于定义组件的事件。通过调用该函数,可以声明组件所触发的事件,并且将事件的名称、参数等信息进行声明。这样,可以在组件内部通过$emit方法来触发自定义事件。
defineExpose:用于定义组件的暴露。通过调用该函数,可以将组件内部的属性或方法暴露给父组件。这样,父组件可以直接访问和调用子组件的内部属性和方法。
defineOptions:用于定义组件的选项。通过调用该函数,可以定义组件的各种选项,如生命周期钩子函数、组件的配置项等。
defineSlots:用于定义组件的插槽。通过调用该函数,可以在组件中定义插槽,并且将插槽的名称、内容等信息进行声明。这样,可以在组件的模板中通过标签来插入父组件传入的内容。
提示:以下是本篇文章正文内容,下面案例可供参考
defineProps
是Vue 3中的一个函数,它的作用是定义组件的属性,类似于Vue 2中的props
选项。
使用defineProps
可以明确指定组件需要接收的属性以及它们的类型、默认值等。这样一来,在组件的使用处,我们就能清晰地看到它所需要的属性,并且能够按照指定的类型进行验证。
使用场景包括但不限于以下情况:
defineProps
来定义。defineProps
来定义。defineProps
可以更好地管理和组织属性的定义。使用场景示例代码如下:
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ description }}</p>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
defineProps({
title: String,
description: {
type: String,
default: 'This is the component description.',
},
});
</script>
在上面的示例中,我们使用了 <script setup>
语法糖来编写组件的逻辑部分。在 defineProps
中我们定义了两个属性:title
和 description
。title
的类型被指定为 String
,而 description
的类型被指定为 String
,并且还定义了一个默认值。
在模板部分,我们直接使用 {{ title }}
和 {{ description }}
来输出 props 的值。
这样,当我们在父组件中使用这个组件时,就可以通过给 title
和 description
属性传入不同的值来动态渲染组件的内容了。
<template>
<div>
<CustomComponent title="This is a custom title" />
<CustomComponent title="Another title" description="This is another description" />
</div>
</template>
<script>
import CustomComponent from './CustomComponent.vue';
export default {
components: {
CustomComponent,
},
};
</script>
在父组件中,我们将 CustomComponent
引入,并通过 title
和 description
属性传入不同的值。根据传入的值,CustomComponent
会渲染不同的标题和描述。
在Vue3中,
defineEmits
是一个用于定义组件的事件的函数。它允许你明确列出组件可以触发的事件,使得组件的使用者更容易理解和使用。
使用<script setup>
语法糖,你可以在组件的顶层中使用defineEmits
函数来定义事件。
下面是一个示例代码,展示了如何使用defineEmits
和<script setup>
来定义组件的事件并在组件中触发这些事件:
<template>
<button @click="onButtonClick">Click me!</button>
</template>
<script setup>
import { defineEmits } from 'vue';
// 定义组件的事件
const emits = defineEmits(['buttonClick']);
// 触发事件
const onButtonClick = () => {
emits('buttonClick', 'Button clicked!');
};
</script>
在上面的示例中,我们通过调用defineEmits
函数来定义了一个名为buttonClick
的事件。然后,我们在onButtonClick
函数中使用emits
来触发这个事件,并传递了一个字符串参数作为事件的payload。
通过使用defineEmits
函数,我们明确了组件可以触发的事件,使得组件使用者能够更容易地了解和使用这些事件。另外,这也提供了一种类型安全的方式来检查事件触发的参数类型。
在 Vue 3 中,
defineExpose
函数用于在组合式 API组件中向父组件暴露方法或属性。它的作用是将一些内部方法或属性暴露给组件外部,使得父组件可以直接访问到。
使用 defineExpose
的场景是,当我们在组合式 API 组件内部定义了一些需要在父组件中使用的方法或属性时,可以通过 defineExpose
将它们暴露出去。
以下是一个使用 defineExpose
的示例代码:
<template>
<div>
<button @click="increaseCounter">Increase Counter</button>
<p>Counter: {{ counter }}</p>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
const counter = ref(0);
const increaseCounter = () => {
counter.value += 1;
};
defineExpose({
counter, // 将 counter 暴露给父组件
increaseCounter, // 将 increaseCounter 方法暴露给父组件
});
</script>
在上面的代码中,我们定义了一个名为 counter
的响应式变量,并通过 increaseCounter
方法将其递增。然后,通过 defineExpose
函数将 counter
变量和 increaseCounter
方法暴露给父组件。
在父组件中,我们可以通过使用组合式 API 组件的 <script setup>
中的 <script>
块的 expose
属性来访问这些暴露出的属性和方法:
<template>
<div>
<ChildComponent ref="childRef" />
<button @click="increaseChildCounter">Increase Child Counter</button>
<p>Child Counter: {{ childCounter }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import ChildComponent from './ChildComponent.vue';
const childRef = ref(null);
let childCounter = null;
onMounted(() => {
childCounter = childRef.value.counter; // 访问子组件暴露的 counter 变量
});
const increaseChildCounter = () => {
childRef.value.increaseCounter(); // 调用子组件暴露的 increaseCounter 方法
};
</script>
在父组件中,我们通过 <ChildComponent ref="childRef" />
的方式引入子组件,并使用 ref
引用子组件实例。然后我们可以通过 childRef.value.counter
访问到子组件暴露的 counter
变量,并通过 childRef.value.increaseCounter()
调用子组件暴露的 increaseCounter
方法。
defineOptions 这个宏可以用来直接在 script setup 中声明组件选项,而不必使用单独的 script 块。用来定义 Options API 的选项。
以下是一个使用 defineOptions
的示例代码:
创建父级ParentLevel.vue
文件
<template>
<div></div>
</template>
<script setup>
import SubLevel from './SubLevel.vue'
console.log('SubLevel', SubLevel);
</script>
创建子级SubLevel.vue
文件
<template>
<div>子级</div>
</template>
<script setup>
defineOptions({
name: 'subLevel',
test: '测试'
})
</script>
在上面的代码中,我们创建了一个父级ParentLevel.vue
文件,并在文件中引入了SubLevel .vue
,并使用console.log
打印出SubLevel
的信息。在子级SubLevel.vue
文件,使用了defineOptions
宏 内容为 { name: ‘subLevel’, test: ‘测试’}。
而在vue3.3之前 是无法暴露出自定义的数据的
Vue 3.3 新增了 defineSlots 宏。我们可以使用 defineSlots 自己定义插槽的类型。这个宏在简单的组件中几乎用不到,但对于一些复杂的组件非常有用,尤其是这个特性与泛型组件一起使用。或是在 Volar 无法正确地推测出类型时,我们可以手动指定。
<script setup lang="ts">
const slots = defineSlots<{
// default 是插槽名称
// 函数的第一个TS对象类型参数是插槽期望接收的 props 的TS类型
// 返回值类型目前被忽略,可以是 any,未来可能利用它来检查插槽内容
default(props: { test: number}): any
}>()
</script>