以下是关于 Vue 组合式API 与 <script setup>
的深度解析与最佳实践指南:
一、组合式API核心思想
1. 逻辑关注点分离
将组件逻辑按功能而非选项(data/methods)拆分,解决选项式API的碎片化问题:
// 传统选项式API的碎片化问题
export default {
data() { return { count: 0 } }, // 状态分散
methods: { increment() { ... } }, // 方法分离
mounted() { ... } // 生命周期分离
}
// 组合式API聚合逻辑
function useCounter() {
const count = ref(0)
const increment = () => count.value++
onMounted(() => console.log('Mounted!'))
return { count, increment }
}
2. 响应式系统核心
ref
:包装基本类型为响应式对象(通过.value
访问)reactive
:创建深层响应式对象(适合复杂数据结构)toRefs
:解构reactive
对象保持响应性
const user = reactive({ name: 'Alice', age: 30 })
const { name, age } = toRefs(user) // 解构后仍保持响应性
二、<script setup>
语法革命
1. 语法糖本质
编译时转换为标准组合式API,减少样板代码:
<!-- 编译前 -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<!-- 编译后 -->
<script>
export default {
setup() {
const count = ref(0)
return { count } // 自动暴露顶层绑定
}
}
</script>
2. 核心特性
- 自动暴露:顶层变量/函数直接模板可用
- 编译器宏:
defineProps
,defineEmits
,defineExpose
- 顶层
await
:直接使用异步操作
<script setup>
// Props声明
const props = defineProps({
title: String,
defaultValue: { type: Number, default: 0 }
})
// 事件发射
const emit = defineEmits(['update:title'])
// 暴露给父组件
defineExpose({ internalMethod: () => {...} })
// 异步数据获取
const data = await fetchData()
</script>
三、最佳实践方案
1. 逻辑复用模式
创建可组合函数(Composables):
// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
const update = e => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
// 组件中使用
<script setup>
import { useMouse } from './useMouse'
const { x, y } = useMouse()
</script>
2. 状态管理策略
- 小型应用:直接使用
reactive
共享状态 - 大型项目:组合
provide/inject
+ Pinia
// 共享状态
const globalState = reactive({ user: null })
// 提供状态
provide('globalState', globalState)
// 注入使用
const injectedState = inject('globalState')
3. 类型安全增强
配合TypeScript实现完整类型推断:
<script setup lang="ts">
interface User {
id: number
name: string
}
// 类型化Props
const props = defineProps<{
user: User
showDetail: boolean
}>()
// 类型化Emit
const emit = defineEmits<{
(e: 'update:user', payload: User): void
(e: 'delete'): void
}>()
</script>
四、性能优化技巧
1. 响应式优化
- 使用
shallowRef
/shallowReactive
避免深层响应 - 利用
computed
缓存计算结果
const heavyList = shallowRef([]) // 仅跟踪.value变化
const filteredList = computed(() =>
heavyList.value.filter(item => item.isActive)
2. 生命周期控制
- 使用
watchEffect
自动清理副作用 - 及时清除定时器/事件监听器
watchEffect((onCleanup) => {
const timer = setInterval(() => {...}, 1000)
onCleanup(() => clearInterval(timer))
})
3. 组件优化
- 使用
v-memo
避免不必要的重渲染 - 拆分大组件为逻辑集中的小型组合
<template>
<div v-memo="[dependency]">
<!-- 仅当dependency变化时重渲染 -->
</div>
</template>
五、常见问题解决方案
1. 模板引用处理
使用ref
+defineExpose
实现组件通信:
<!-- Child.vue -->
<script setup>
const inputRef = ref(null)
defineExpose({ focus: () => inputRef.value.focus() })
</script>
<template>
<input ref="inputRef">
</template>
<!-- Parent.vue -->
<template>
<Child ref="childRef" />
</template>
<script setup>
const childRef = ref(null)
const focusInput = () => childRef.value.focus()
</script>
2. 路由状态管理
与Vue Router深度集成:
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
watch(() => route.params.id, (newId) => {
fetchData(newId)
})
3. 样式作用域
结合scoped
与CSS变量:
<style scoped>
.button {
color: var(--theme-color);
}
</style>
六、升级迁移策略
1. 渐进式迁移
- 新组件使用
<script setup>
- 旧组件逐步重构为组合式API
- 使用
@vue/compat
进行兼容过渡
2. 工具链支持
- Vite默认支持组合式API
- Vue CLI需升级至v5+
- ESLint配置
vue/setup-compiler-macros
通过组合式API与<script setup>
的配合,开发者可以构建出 更灵活、更易维护 的Vue 3应用。关键要把握:
- 逻辑关注点聚合:通过组合函数实现高内聚
- 响应式精准控制:理解
ref
/reactive
适用场景 - 工程化实践:结合TypeScript和现代构建工具提升质量