什么是 setup 函数?

setup 是 Vue 3 组合式 API 的核心和入口。可以把它理解为组件的"控制中心"——所有组件的逻辑都在这里组织和执行。

执行时机与特点

export default {
  setup() {
    console.log('setup 执行了')
  },
  beforeCreate() {
    console.log('beforeCreate 执行了')
  },
  created() {
    console.log('created 执行了')
  }
}

执行顺序: setup → beforeCreate → created

重要特性: 在 setup 中无法访问 this,因为此时组件实例还没有创建完成。

setup 的参数解析

setup 函数接收两个重要的参数:

1. props - 接收父组件传递的数据

export default {
  props: ['title', 'content'],
  setup(props) {
    // 访问 props
    console.log(props.title)    // 获取 title
    console.log(props.content)  // 获取 content
    
    // props 是响应式的,可以使用 watch 监听
    watch(() => props.title, (newVal, oldVal) => {
      console.log(`title 从 ${oldVal} 变为 ${newVal}`)
    })
    
    return {}
  }
}

2. context - 组件的上下文信息

context 是一个普通对象,包含三个常用属性:

export default {
  setup(props, context) {
    // 1. attrs - 获取未在 props 中声明的属性
    console.log(context.attrs.class)  // 获取 class 属性
    console.log(context.attrs.style)  // 获取 style 属性
    
    // 2. slots - 访问插槽内容
    console.log(context.slots.default) // 默认插槽
    console.log(context.slots.header)  // 具名插槽
    
    // 3. emit - 触发自定义事件
    const handleClick = () => {
      context.emit('update', '新数据')
    }
    
    return {
      handleClick
    }
  }
}

更常用的解构写法:

setup(props, { attrs, slots, emit }) {
  // 直接使用 attrs、slots、emit
}

setup 的返回值

setup 必须返回一个对象,这个对象中的属性和方法可以在模板中直接使用:

import { ref, computed } from 'vue'

export default {
  setup() {
    // 响应式数据
    const count = ref(0)
    const name = ref('张三')
    
    // 计算属性
    const doubleCount = computed(() => count.value * 2)
    
    // 方法
    const increment = () => {
      count.value++
    }
    
    const reset = () => {
      count.value = 0
      name.value = '张三'
    }
    
    // 返回给模板使用
    return {
      count,
      name,
      doubleCount,
      increment,
      reset
    }
  }
}

在模板中直接使用:

<template>
  <div>
    <p>{{ name }}的计数器:{{ count }}</p>
    <p>双倍:{{ doubleCount }}</p>
    <button @click="increment">+1</button>
    <button @click="reset">重置</button>
  </div>
</template>

实际开发示例

用户管理组件

<template>
  <div>
    <input v-model="userForm.name" placeholder="姓名">
    <input v-model="userForm.age" placeholder="年龄">
    <button @click="addUser" :disabled="!isFormValid">添加用户</button>
    
    <ul>
      <li v-for="user in users" :key="user.id">
        {{ user.name }} - {{ user.age }}岁
      </li>
    </ul>
  </div>
</template>

<script>
import { ref, reactive, computed } from 'vue'

export default {
  setup() {
    // 响应式数据
    const users = ref([])
    const userForm = reactive({
      name: '',
      age: ''
    })
    
    // 计算属性
    const isFormValid = computed(() => {
      return userForm.name.trim() && userForm.age
    })
    
    // 方法
    const addUser = () => {
      if (!isFormValid.value) return
      
      users.value.push({
        id: Date.now(),
        name: userForm.name,
        age: userForm.age
      })
      
      // 重置表单
      userForm.name = ''
      userForm.age = ''
    }
    
    return {
      users,
      userForm,
      isFormValid,
      addUser
    }
  }
}
</script>

结合生命周期钩子

在 setup 中使用生命周期函数:

import { onMounted, onUpdated, onUnmounted } from 'vue'

export default {
  setup() {
    const data = ref(null)
    
    onMounted(() => {
      console.log('组件挂载完成')
      // 在这里可以执行初始化操作,比如请求数据
    })
    
    onUpdated(() => {
      console.log('组件更新了')
    })
    
    onUnmounted(() => {
      console.log('组件卸载了')
      // 在这里可以执行清理操作
    })
    
    return {
      data
    }
  }
}

<script setup> 语法糖

Vue 3.2 引入了更简洁的 <script setup> 语法:

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">+1</button>
  </div>
</template>

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

// 变量和函数自动暴露给模板
const count = ref(0)
const increment = () => {
  count.value++
}

// 定义 props 和 emits
defineProps({
  title: String
})

defineEmits(['update'])
</script>

总结

setup 函数是 Vue 3 组合式 API 的基石,它:

  • 提供了统一的逻辑组织方式
  • 接收 props 和 context 参数
  • 通过返回值暴露模板需要的内容
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐