一、setup函数生命周期与执行时机

1.1 核心执行机制

setup函数是组合式API的入口,其执行时机早于所有选项式生命周期钩子:

export default {
  setup() {
    console.log('setup执行') // 最先执行
    // beforeCreate/created阶段的操作可在此完成
  },
  beforeCreate() {
    console.log('beforeCreate执行')
  }
}

1.2 生命周期映射表

选项式API 组合式API
beforeCreate 无需使用
created 无需使用
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured

1.3 使用示例

import { onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    onMounted(() => {
      console.log('组件已挂载')
      window.addEventListener('resize', handleResize)
    })

    onUnmounted(() => {
      window.removeEventListener('resize', handleResize)
    })

    const handleResize = () => {
      /* 处理逻辑 */
    }
  }
}

二、逻辑复用模式:自定义Hook开发

2.1 Hook规范原则

  1. 命名遵循useXxx格式
  2. 返回响应式数据+方法的集合
  3. 自动管理副作用清理

2.2 鼠标追踪案例

// useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useMousePosition() {
  const x = ref(0)
  const y = ref(0)

  const update = (e) => {
    x.value = e.clientX
    y.value = e.clientY
  }

  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  return { x, y }
}

2.3 组件中使用Hook

import { useMousePosition } from './hooks/useMousePosition'

export default {
  setup() {
    const { x, y } = useMousePosition()
    
    return { x, y }
  }
}

2.4 参数化Hook示例

// useInterval.js
import { onUnmounted } from 'vue'

export function useInterval(fn, delay) {
  const timer = setInterval(fn, delay)
  onUnmounted(() => clearInterval(timer))
  return timer
}

// 组件内使用
useInterval(() => {
  console.log('定时执行')
}, 1000)

三、<script setup>语法糖最佳实践

3.1 基本范式

<script setup>
import { ref } from 'vue'

const count = ref(0)
const increment = () => count.value++
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

3.2 属性与事件

<script setup>
const props = defineProps({
  title: String
})

const emit = defineEmits(['update'])
</script>

3.3 组件方法暴露

<script setup>
import { defineExpose } from 'vue'

const publicMethod = () => {
  // 逻辑代码
}

defineExpose({
  publicMethod
})
</script>

3.4 异步组件处理

<script setup>
const data = await fetchData()
</script>

<template>
  <!-- 自动包裹在Suspense中 -->
  {{ data }}
</template>

3.5 代码组织规范

  1. 推荐结构顺序:
// 1. 外部导入
import { ... } from 'vue'
// 2. 组件props定义
const props = defineProps(...)
// 3. 响应式状态
const state = ref(...)
// 4. 计算属性
const computedValue = computed(...)
// 5. 方法声明
function doSomething() {...}
// 6. 生命周期
onMounted(...)
// 7. watch监听
watch(...)
// 8. 暴露接口
defineExpose(...)

3.6 TS类型支持

<script setup lang="ts">
interface Props {
  title: string
  count?: number
}

const props = defineProps<Props>()
</script>

四、综合应用实例

<script setup>
import { useMousePosition } from '@/hooks/useMouse'
import { computed } from 'vue'

const { x, y } = useMousePosition()

const distance = computed(() => {
  return Math.sqrt(x.value ** 2 + y.value ** 2)
})
</script>

<template>
  <div class="coord">
    X: {{ x }}, Y: {{ y }}
    <div>Distance: {{ distance.toFixed(2) }}</div>
  </div>
</template>

通过组合式API,我们可以实现:

  1. 业务逻辑的高效复用
  2. 组件代码的语义化组织
  3. 类型系统的完美支持
  4. 自动化的副作用清理
  5. 更灵活的逻辑组合方式

建议开发时遵循"单一职责"原则,将复杂逻辑拆解为多个独立Hook,通过<script setup>语法实现更简洁的组件表达。