Vue 组合式API 与 <script setup> 的深度解析

以下是关于 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应用。关键要把握:

  1. 逻辑关注点聚合:通过组合函数实现高内聚
  2. 响应式精准控制:理解ref/reactive适用场景
  3. 工程化实践:结合TypeScript和现代构建工具提升质量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小赖同学啊

感谢上帝的投喂

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值