Vue 3 Setup语法糖实战指南:提升开发效率的技巧与踩坑经验
直接上代码,别整那些虚的
我从去年开始在项目里全面用 <script setup> 语法糖,说实话,真香。以前写 Composition API 要手动 return 一堆变量和函数,现在直接在顶层写,省事太多。刚上手时我也怀疑过:这玩意儿真能替代 Options API 吗?折腾了几个项目后,结论是:90% 的场景完全够用,剩下的 10% 也能绕过去。
先看一个最基础的例子:
<script setup>
import { ref, onMounted } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
onMounted(() => {
console.log('组件挂载了')
})
</script>
<template>
<div>
<p>{{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
注意,这里没有 export default,没有 setup() 函数,所有顶层声明的变量和函数在模板里直接可用。亲测有效,而且 IDE 补全也完全没问题(前提是你的 VSCode 装了 Volar)。
这个场景最好用:props 和 emits
很多人一开始卡在怎么定义 props 和 emits。其实很简单,用 defineProps 和 defineEmits,这两个是编译时宏,不需要 import。
<script setup>
const props = defineProps({
title: {
type: String,
required: true
},
maxCount: {
type: Number,
default: 10
}
})
const emit = defineEmits(['update', 'close'])
function handleClose() {
emit('close')
}
</script>
这里注意下,我踩过坑:如果你用 TypeScript,可以直接写类型定义,但 JS 项目就老老实实用对象形式。另外,defineProps 和 defineEmits 必须写在顶层,不能包在函数或条件里,否则编译器会报错。
踩坑提醒:这三点一定注意
用 <script setup> 不是无脑爽,有几个坑我踩过好几次,分享出来帮你省点时间:
- 无法访问 this:因为根本没 this,所以别想用
this.$emit或this.$refs。emits 用defineEmits,refs 用ref+ 模板引用。 - 动态组件名不能直接写字符串:比如你想用
<component :is="MyComponent" />,但 MyComponent 是在 setup 里 import 的,这时候必须把变量暴露出去。不过好消息是,<script setup>会自动把 import 的组件注册到模板,所以你直接写组件名就行,不用额外处理。 - 命名冲突很隐蔽:如果你在 setup 里声明了一个叫
loading的变量,又在 props 里定义了loading,Vue 会优先用 props 的值。这在调试时特别容易懵,建议命名时加个前缀,比如localLoading。
高级技巧:配合 useXXX 组合函数
我现在的项目里,几乎每个组件都拆成一堆 useXXX 的组合函数。比如表单逻辑、数据请求、本地存储,全抽出去。配合 <script setup> 简直天作之合。
// composables/useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0, max = 10) {
const count = ref(initialValue)
const isMax = computed(() => count.value >= max)
function increment() {
if (!isMax.value) count.value++
}
function reset() {
count.value = initialValue
}
return {
count,
isMax,
increment,
reset
}
}
<script setup>
import { useCounter } from '@/composables/useCounter'
const { count, isMax, increment, reset } = useCounter(0, 5)
</script>
<template>
<div>
<p :class="{ 'text-red-500': isMax }">{{ count }}</p>
<button @click="increment" :disabled="isMax">+1</button>
<button @click="reset">重置</button>
</div>
</template>
这种写法逻辑清晰,测试也好写。而且组合函数可以复用,比如另一个组件也要计数器,直接 import 就行。建议直接用这种方式,别再把逻辑塞在组件里了。
不是万能药,但够用了
虽然 <script setup> 好用,但也不是所有情况都适合。比如你需要动态修改组件选项(像 name、inheritAttrs),就得用普通的 <script> 再加一个 <script setup>。不过这种情况很少,我一年也就遇到两三次。
另外,异步 setup 也是支持的。比如你有个组件需要等接口返回才能渲染,可以这样写:
<script setup>
import { ref } from 'vue'
import { fetchData } from '@/api'
const data = ref(null)
const loading = ref(true)
// 顶层 await 只在 Vue 3.3+ 支持
const res = await fetchData()
data.value = res.data
loading.value = false
</script>
但注意,顶层 await 会阻塞组件渲染,所以一般我会配合 suspense 使用。不过如果你项目还没升级到 3.3,就还是用 onMounted 里调接口吧,别折腾。
最后说两句
总的来说,<script setup> 是 Vue 3 里最值得拥抱的特性之一。它让代码更简洁,逻辑更聚焦,团队协作时也更容易理解。虽然有些小限制,但瑕不掩瑜。
以上是我踩坑后的总结,希望对你有帮助。这个技巧的拓展用法还有很多,比如和 TypeScript 深度集成、自定义宏、配合 Pinia 等,后续会继续分享这类博客。有更优的实现方式欢迎评论区交流,毕竟前端这行,谁还没被新语法虐过几次呢?

暂无评论