总结
Vue 3 提供了多种 API 来定义和管理组件,包括:
- 组件定义:使用
defineComponent
,定义组件的data
、props
、methods
、emits
等。 - 组合 API:使用
setup
、ref
、reactive
、computed
、watch
和watchEffect
。 - 生命周期钩子:如
onMounted
、onUpdated
等。 provide
和inject
:在组件树中传递和接收数据。- 异步组件:使用
defineAsyncComponent
按需加载组件。 useSlots
和useAttrs
:访问组件插槽和属性。
这些 API 使得 Vue 3 组件的定义和管理更加灵活和强大。
1. 组件定义
使用 defineComponent
基本用法
defineComponent
是 Vue 3 中用于定义组件的一个 API,特别是在使用 TypeScript 时,它提供了类型安全和代码提示。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'MyComponent',
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
},
});
组件选项
定义 data
:是定义组件的响应式数据。虽然在 Vue 3 的组合 API 中,使用 setup
和 ref
、reactive
是更推荐的方式,但你仍然可以使用 data
选项来定义状态。
export default defineComponent({
data() {
return {
count: 0,
message: 'Hello Vue 3'
};
}
});
定义 props
:用于定义组件可以接收的属性。在 defineComponent
中,你可以使用对象语法来定义属性的类型、默认值和其他选项。
export default defineComponent({
props: {
title: {
type: String, // 属性类型
required: true, // 是否是必需的
},
count: {
type: Number,
default: 0 // 默认值
}
}
});
定义 emits:
用于定义组件发射的事件。你可以指定一个事件的列表,也可以定义事件验证函数来确保事件名称和参数正确。
import { defineComponent } from 'vue';
export default defineComponent({
emits: ['update'],
methods: {
update() {
this.$emit('update');
}
}
});
定义 methods
:用于定义组件的方法,这些方法可以在模板中调用。
export default defineComponent({
methods: {
greet() {
console.log('Hello!');
}
}
});
2.组合 API
setup
函数:
Vue 3 组合 API 的核心。你可以在 setup
中定义响应式数据、计算属性、方法、生命周期钩子等。
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup(props, { emit }) {
const count = ref(0);
const increment = () => {
count.value++;
emit('update', count.value); // 使用 emit 发射事件
};
return { count, increment };
}
});
定义计算属性 (computed
)
import { defineComponent, computed, ref } from 'vue';
export default defineComponent({
setup() {
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
return { firstName, lastName, fullName };
}
});
3.使用生命周期钩子
Vue 3 提供了组合 API 风格的生命周期钩子,类似于 Vue 2 中的生命周期选项,但在 setup
中使用。
import { defineComponent, onMounted, onUnmounted } from 'vue';
export default defineComponent({
setup() {
onMounted(() => {
console.log('Component has been mounted');
});
onUnmounted(() => {
console.log('Component has been unmounted');
});
}
});
4.使用 provide
和 inject:
用于在组件树中提供和注入依赖数据。
在父组件中 provide
数据:
import { defineComponent, provide, ref } from 'vue';
export default defineComponent({
setup() {
const theme = ref('dark');
provide('theme', theme);
}
});
在子组件中 inject
数据:
import { defineComponent, inject } from 'vue';
export default defineComponent({
setup() {
const theme = inject('theme', 'light'); // 第二个参数是默认值
return { theme };
}
});
5. 异步组件:defineAsyncComponent
defineAsyncComponent
用于定义按需加载的异步组件。异步组件允许你在需要的时候动态加载组件,从而减少初始加载时间,提高应用性能。你可以通过一个工厂函数来定义一个异步组件,该函数返回一个 Promise
,该 Promise
解析后会返回实际的组件。
基本用法
使用 defineAsyncComponent
按需加载一个组件:
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>
import('./MyAsyncComponent.vue') // 动态导入组件
);
使用异步组件
在父组件中,你可以像使用常规组件一样使用异步组件:
<template>
<div>
<!-- 使用异步组件 -->
<AsyncComponent />
</div>
</template>
<script>
import { defineComponent } from 'vue';
import AsyncComponent from './AsyncComponent'; // 导入异步组件
export default defineComponent({
components: {
AsyncComponent
}
});
</script>
配置选项
defineAsyncComponent
还支持一些额外的配置选项,例如用于设置加载组件、错误组件和超时时间等:
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent({
loader: () => import('./MyAsyncComponent.vue'), // 必须:动态导入组件
loadingComponent: LoadingComponent, // 可选:加载状态组件
errorComponent: ErrorComponent, // 可选:错误状态组件
delay: 200, // 可选:在显示加载组件之前的延迟时间(毫秒)
timeout: 3000, // 可选:超时之后显示错误组件的时间(毫秒)
onError(error, retry, fail, attempts) {
if (attempts <= 3) { // 最大重试次数
retry(); // 重试加载
} else {
fail(); // 失败处理
}
}
});
6. useSlots
和 useAttrs
useSlots
和 useAttrs
是 Vue 3 中提供的组合 API,用于访问组件的插槽 (slots
) 和属性 (attrs
)。这些 API 可以让你在 setup
函数中更直接地访问组件的插槽内容和非 props
的属性。
useSlots
useSlots
函数用于在组合 API 中访问当前组件的插槽内容。它返回一个对象,该对象包含所有命名插槽的函数,函数返回插槽内容的 VNode
数组。
使用示例:
<template>
<div>
<!-- 使用具名插槽 -->
<slot name="header">Default Header</slot>
<slot>Default Content</slot>
<slot name="footer">Default Footer</slot>
</div>
</template>
<script>
import { defineComponent, useSlots } from 'vue';
export default defineComponent({
setup() {
const slots = useSlots();
// 使用插槽
if (slots.header) {
console.log('Header slot is provided');
}
return {};
}
});
</script>
useAttrs
useAttrs
函数用于在组合 API 中访问传递给当前组件的非 props
的特性(例如自定义 HTML 属性)。useAttrs
返回一个响应式对象,该对象包含所有这些特性。
使用示例:
<template>
<div v-bind="attrs">
<!-- 使用组件传入的属性 -->
<p>{{ attrs.someAttr }}</p>
</div>
</template>
<script>
import { defineComponent, useAttrs } from 'vue';
export default defineComponent({
setup() {
const attrs = useAttrs(); // 获取非 props 属性
return { attrs };
}
});
</script>
组合使用示例
你可以同时使用 useSlots
和 useAttrs
来处理插槽和非 props
的属性:
<template>
<div v-bind="attrs">
<header>
<slot name="header">Default Header</slot>
</header>
<main>
<slot>Default Content</slot>
</main>
<footer>
<slot name="footer">Default Footer</slot>
</footer>
</div>
</template>
<script>
import { defineComponent, useSlots, useAttrs } from 'vue';
export default defineComponent({
setup() {
const slots = useSlots(); // 获取插槽
const attrs = useAttrs(); // 获取非 props 的属性
return { slots, attrs };
}
});
</script>
总结
defineAsyncComponent
用于按需加载组件,可以提高性能。useSlots
提供访问插槽内容的功能,适用于组合 API。useAttrs
提供访问非props
属性的功能,使得组件更加灵活。
这些 API 都使得 Vue 3 在处理组件逻辑、动态加载和插槽方面更加灵活和高效。