Vue3的
<script setup>语法相比传统Options API写法更加简洁高效。
它通过编译宏如
defineProps、defineEmits等替代了defineComponent,减少了样板代码,同时提供更好的TypeScript支持。
在
<script setup>中,响应式数据、方法、生命周期等都可以直接编写,代码组织更接近Composition API逻辑。
虽然仍支持与Options API混用,但推荐使用纯
<script setup>写法,这是Vue3推荐的开发方式,能自动编译为组件选项,使开发更加高效简洁。
在 <script setup> 中不需要使用 defineComponent
传统写法 vs <script setup>
1. 传统 Options API 写法
javascript
<!-- 需要 defineComponent -->
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'MyComponent',
props: {
title: String
},
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
});
</script>
2. 使用 <script setup>(推荐)
TypeScript
<!-- 不需要 defineComponent -->
<script setup lang="ts">
import { ref } from 'vue';
// Props 定义
const props = defineProps<{
title: string;
}>();
// 响应式数据
const count = ref(0);
// 方法
const increment = () => {
count.value++;
};
</script>
<script setup> 中的替代 API
1. 定义 Props
TypeScript
<script setup lang="ts">
// 方式1:使用泛型(推荐)
defineProps<{
title: string;
count?: number;
items: string[];
}>();
// 方式2:使用运行时声明
defineProps({
title: String,
count: {
type: Number,
default: 0
}
});
// 方式3:混合使用(Vue 3.3+)
interface Props {
title: string;
count?: number;
}
defineProps<Props>();
</script>
2. 定义 Emits
TypeScript
<script setup lang="ts">
// 方式1:使用泛型
const emit = defineEmits<{
(e: 'update', value: string): void;
(e: 'submit', payload: { id: number }): void;
}>();
// 方式2:数组形式
const emit = defineEmits(['update', 'submit']);
// 方式3:对象形式(带验证)
const emit = defineEmits({
update: (value: string) => typeof value === 'string',
submit: (payload: { id: number }) => payload.id > 0
});
</script>
3. 定义 Slots 和 Attrs
TypeScript
<script setup lang="ts">
import { useSlots, useAttrs } from 'vue';
const slots = useSlots();
const attrs = useAttrs();
</script>
4. 定义 Expose
TypeScript
<script setup lang="ts">
import { ref } from 'vue';
const inputRef = ref<HTMLInputElement>();
// 暴露给父组件的方法
defineExpose({
focus: () => inputRef.value?.focus(),
clear: () => {
if (inputRef.value) inputRef.value.value = '';
}
});
</script>
为什么不需要 defineComponent?
<script setup> 的优势:
-
自动编译 :
<script setup>会在编译时转换为正常的组件选项 -
更简洁:减少样板代码
-
更好的类型推断:TypeScript 支持更好
-
更直观:代码组织更接近 Composition API 的逻辑
编译对比:
javascript
// <script setup> 代码
<script setup lang="ts">
const count = ref(0);
</script>
// 编译后的结果 ≈
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const count = ref(0);
return { count };
}
});
</script>
特殊情况处理
1. 如果需要组件名(用于调试或递归组件)
TypeScript
<!-- 方式1:使用两个 script 标签 -->
<script lang="ts">
export default {
name: 'MyComponent'
};
</script>
<script setup lang="ts">
// Composition API 代码
const count = ref(0);
</script>
<!-- 方式2:使用插件(Vue 3.3+) -->
<script setup lang="ts">
defineOptions({
name: 'MyComponent',
inheritAttrs: false
});
</script>
2. 混合使用 Options API
虽然不推荐,但如果需要:
TypeScript
<script setup lang="ts">
// Composition API 部分
const count = ref(0);
</script>
<script lang="ts">
import { defineComponent } from 'vue';
// Options API 部分
export default defineComponent({
name: 'MyComponent',
// 这里可以添加 computed, watch 等
computed: {
doubled() {
// 注意:无法直接访问 setup 中的变量
return 0;
}
}
});
</script>
完整示例
TypeScript
<template>
<div>
<h1>{{ title }}</h1>
<p>计数: {{ count }}</p>
<button @click="increment">增加</button>
<button @click="handleSubmit">提交</button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
// Props
interface Props {
title: string;
initialCount?: number;
}
const props = withDefaults(defineProps<Props>(), {
initialCount: 0
});
// Emits
const emit = defineEmits<{
(e: 'update:count', value: number): void;
(e: 'submit', payload: { count: number }): void;
}>();
// 状态
const count = ref(props.initialCount);
// 方法
const increment = () => {
count.value++;
emit('update:count', count.value);
};
const handleSubmit = () => {
emit('submit', { count: count.value });
};
// 生命周期
onMounted(() => {
console.log('组件已挂载');
});
// 暴露给父组件
defineExpose({
reset: () => {
count.value = 0;
}
});
</script>
<style scoped>
/* 样式 */
</style>
总结
在 <script setup> 中:
-
✅ 不需要
defineComponent -
✅ 使用
defineProps、defineEmits、defineExpose等编译宏 -
✅ 代码更简洁,类型支持更好
-
✅ 是 Vue 3 的推荐写法
只有在使用传统 Options API 写法时才需要 defineComponent,而 <script setup> 是 Composition API 的语法糖,会自动处理这些。