Vue3 script setup与defineProps/defineEmits
解释Vue3 <script setup>语法糖的核心特性,以及defineProps、defineEmits、defineExpose等编译宏的作用原理。<script setup>相比普通setup函数有哪些编译优化?
回答
苦行僧
<script setup>核心特性
<script setup>
import { ref } from 'vue';
const count = ref(0);
const inc = () => count.value++;
</script>
<template>
<button @click="inc">{{ count }}</button>
</template>
编译宏(Compiler Macros)
defineProps:声明props,类型推断自动推导
const props = defineProps({
title: String,
count: { type: Number, default: 0 }
});
// 或纯类型声明
const props = defineProps<{ title: string; count?: number }>();
defineEmits:声明emit事件
const emit = defineEmits<{
(e: 'update', id: number): void;
(e: 'delete'): void;
}>();
// 或运行时声明
const emit = defineEmits(['update', 'delete']);
defineExpose:暴露组件内部属性和方法给父组件(通过模板ref)
const api = { validate() { ... }, reset() { ... } };
defineExpose(api);
// 父组件:<Comp ref="compRef" /> -> compRef.value.validate()
withDefaults:为类型声明props提供默认值
const props = withDefaults(defineProps<{ count?: number }>(), {
count: 0
});
编译优化
- 编译时提升:静态模板在编译时提升(无需每次渲染重建)
- 静态Props:
v-bind:id="'static'"编译为直接属性赋值 - PatchFlags:生成细粒度更新标记,运行时更高效的diff
- HoistStatic:静态节点提升到渲染函数之外
- 无需return:顶层绑定自动暴露给模板(比普通setup省去return)
普通setup vs script setup
| 方面 | setup() | script setup |
|---|---|---|
| 语法 | 需return,模板用this.xxx | 自动暴露,更简洁 |
| TypeScript | 类型推断弱 | 强类型推断(宏) |
| 组件注册 | components选项导入 | 直接import在模板使用 |
| 性能 | 标准 | 更多编译时优化 |
注意事项:
- 不能使用
export default(自动生成) - 通过
useSlots()和useAttrs()代替$slots和$attrs - defineProps/defineEmits无需额外导入,是编译时宏