1. Vue3 <script setup> 语法糖的革命性变化
在Vue3的Composition API中,<script setup> 语法糖彻底改变了我们编写组件的方式。这个特性自Vue 3.2版本正式发布以来,已经成为现代Vue开发的标配写法。它通过编译时的语法转换,让我们可以用更简洁的代码实现相同的功能。
传统Options API写法需要在export default中定义各种选项,而Composition API虽然提供了更好的逻辑组织方式,但仍然需要显式地返回模板中使用的变量和方法。<script setup>的出现解决了这个问题,它让组件的编写变得更加直观和高效。
重要提示:
<script setup>是在单文件组件(SFC)中使用的编译时语法糖,它会在编译阶段被转换为标准的Composition API代码。这意味着它不会增加运行时开销,却能提供更好的开发体验。
1.1 为什么可以省略defineComponent
在标准Composition API中,我们通常需要使用defineComponent来定义组件:
javascript复制import { defineComponent } from 'vue'
export default defineComponent({
setup() {
// 组件逻辑
return {
// 暴露给模板的内容
}
}
})
而在<script setup>中,这一切都变得简单了:
vue复制<script setup>
// 直接在这里写组件逻辑
</script>
这种写法之所以可行,是因为<script setup>在编译时会自动将所有顶层绑定(变量、函数等)暴露给模板。编译器会为我们处理所有必要的包装工作,包括自动推断组件选项、处理props和emits等。
2. <script setup>的核心特性解析
2.1 自动的顶层绑定暴露
在<script setup>中声明的任何顶级变量、函数或import都会自动成为模板的可用内容。这意味着你不再需要手动从setup函数中返回它们:
vue复制<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
// 这些都会自动暴露给模板
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
这种自动暴露机制大大简化了代码,减少了样板代码的编写。编译器会分析<script setup>块中的所有顶层绑定,并自动生成对应的模板作用域。
2.2 编译器宏的使用
<script setup>引入了一系列编译器宏,这些特殊的函数在编译时会被处理,不会出现在运行时代码中:
- defineProps - 定义组件接收的props
- defineEmits - 定义组件触发的事件
- defineExpose - 明确指定组件暴露给父组件的内容
- useSlots和useAttrs - 访问插槽和属性
这些宏之所以不需要导入就能使用,是因为它们是由Vue编译器特殊处理的。在编译阶段,它们会被转换为标准的组件选项。
2.2.1 defineProps的典型用法
vue复制<script setup>
const props = defineProps({
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
})
</script>
2.2.2 defineEmits的典型用法
vue复制<script setup>
const emit = defineEmits(['update', 'delete'])
function handleClick() {
emit('update', newValue)
}
</script>
注意事项:这些编译器宏必须在
<script setup>的顶层作用域中使用,不能在函数内部或其他块级作用域中使用,否则会导致编译错误。
3. 与传统写法的对比分析
3.1 代码量对比
让我们通过一个简单的计数器组件来对比不同写法的代码量:
Options API写法:
vue复制<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
</script>
标准Composition API写法:
vue复制<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
const increment = () => count.value++
return {
count,
increment
}
}
})
</script>
