Vue 3 Setup语法糖实战指南:提升开发效率的技巧与踩坑经验

Prog.福萍 框架 阅读 611
赞 82 收藏
二维码
手机扫码查看
反馈

直接上代码,别整那些虚的

我从去年开始在项目里全面用 <script setup> 语法糖,说实话,真香。以前写 Composition API 要手动 return 一堆变量和函数,现在直接在顶层写,省事太多。刚上手时我也怀疑过:这玩意儿真能替代 Options API 吗?折腾了几个项目后,结论是:90% 的场景完全够用,剩下的 10% 也能绕过去。

Vue 3 Setup语法糖实战指南:提升开发效率的技巧与踩坑经验

先看一个最基础的例子:

<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。其实很简单,用 definePropsdefineEmits,这两个是编译时宏,不需要 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 项目就老老实实用对象形式。另外,definePropsdefineEmits 必须写在顶层,不能包在函数或条件里,否则编译器会报错。

踩坑提醒:这三点一定注意

<script setup> 不是无脑爽,有几个坑我踩过好几次,分享出来帮你省点时间:

  • 无法访问 this:因为根本没 this,所以别想用 this.$emitthis.$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> 好用,但也不是所有情况都适合。比如你需要动态修改组件选项(像 nameinheritAttrs),就得用普通的 <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 等,后续会继续分享这类博客。有更优的实现方式欢迎评论区交流,毕竟前端这行,谁还没被新语法虐过几次呢?

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论