Vue3的defineComponent是定义组件的核心方法,支持选项式API和组合式API两种写法,提供完善的TypeScript类型推断。
主要特性包括:
- 支持props、emits的类型定义;
- 可与自定义Hooks结合使用;
- 提供泛型组件支持;
- 在<script setup>语法糖中自动推断类型。
相比Vue2,defineComponent为组件开发带来更好的类型安全性和IDE支持,特别适合TypeScript项目,使代码更易维护。
使用时可选择传统选项式或更灵活的组合式API,复杂组件推荐采用组合式API以获得更好的代码组织。
defineComponent 是 Vue 3 中用于定义组件的主要方法,它提供了更好的 TypeScript 类型推断支持。
基本用法
1. 选项式 API(类似 Vue 2)
javascript
import { defineComponent } from 'vue'
export default defineComponent({
name: 'MyComponent',
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
},
data() {
return {
message: 'Hello Vue 3'
}
},
computed: {
doubledCount() {
return this.count * 2
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
console.log('组件已挂载')
}
})
2. 组合式 API
javascript
import { defineComponent, ref, computed, onMounted } from 'vue'
export default defineComponent({
name: 'MyComponent',
props: {
title: String
},
setup(props) {
const count = ref(0)
const message = ref('Hello Vue 3')
const doubledCount = computed(() => count.value * 2)
const increment = () => {
count.value++
}
onMounted(() => {
console.log('组件已挂载')
})
return {
count,
message,
doubledCount,
increment
}
}
})
TypeScript 支持
3. 完整的 TypeScript 类型定义
TypeScript
import { defineComponent, PropType } from 'vue'
interface User {
id: number
name: string
email: string
}
export default defineComponent({
name: 'UserProfile',
props: {
// 基本类型
age: {
type: Number,
required: true
},
// 自定义类型
user: {
type: Object as PropType<User>,
required: true
},
// 数组类型
tags: {
type: Array as PropType<string[]>,
default: () => []
},
// 联合类型
status: {
type: String as PropType<'active' | 'inactive' | 'pending'>,
default: 'pending'
}
},
emits: {
// 定义 emit 事件
'update:name': (value: string) => true,
'delete': (id: number) => true
},
setup(props, { emit }) {
// 这里可以获得完整的类型提示
console.log(props.user.name) // 类型安全
const updateName = (name: string) => {
emit('update:name', name)
}
return {
updateName
}
}
})
多种写法
4. 函数式写法
TypeScript
import { defineComponent, h } from 'vue'
// 函数式组件
const FunctionalComponent = defineComponent(() => {
return () => h('div', 'Hello Functional Component')
})
// 带 props 的函数式组件
const Greeting = defineComponent((props: { name: string }) => {
return () => h('div', `Hello ${props.name}`)
})
5. Setup 语法糖(<script setup>)
vue
TypeScript
<script setup lang="ts">
import { defineProps, defineEmits, ref } from 'vue'
// 定义 props(自动推断类型)
const props = defineProps<{
title: string
count?: number
}>()
// 定义 emits
const emit = defineEmits<{
(e: 'update:title', value: string): void
(e: 'submit'): void
}>()
const message = ref('Hello')
// 直接使用,不需要 return
</script>
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ message }}</p>
</div>
</template>
高级用法
6. 泛型组件
TypeScript
import { defineComponent, PropType } from 'vue'
// 使用泛型定义可复用的组件
function useGenericComponent<T>() {
return defineComponent({
props: {
items: {
type: Array as PropType<T[]>,
required: true
},
itemFormatter: {
type: Function as PropType<(item: T) => string>,
default: (item: T) => String(item)
}
}
})
}
// 使用
const StringList = useGenericComponent<string>()
const NumberList = useGenericComponent<number>()
7. 与自定义 Hooks 结合
TypeScript
import { defineComponent } from 'vue'
import { useUser, useApi } from './composables'
export default defineComponent({
name: 'UserProfile',
setup() {
// 使用自定义组合式函数
const { user, loading, fetchUser } = useUser()
const { callApi } = useApi()
// 组合多个逻辑
const loadData = async () => {
await fetchUser()
await callApi('/some-endpoint')
}
return {
user,
loading,
loadData
}
}
})
主要优势
-
类型推断:为选项式 API 提供更好的 TypeScript 类型支持
-
类型安全:props、emits、data 等都有完整的类型检查
-
IDE 支持:更好的代码补全和提示
-
灵活性:支持多种组件定义方式
注意事项
-
在
<script setup>中,defineComponent不是必须的,但可以用来包裹组件逻辑 -
对于简单的组件,可以直接使用
defineComponent({}) -
对于复杂组件,建议使用组合式 API 以获得更好的类型支持和代码组织
Vue 3 的 defineComponent 让组件开发更加类型安全和易于维护,特别是在 TypeScript 项目中优势明显。