模式切换
setup() 函数
setup()
是 Vue 3 组合式 API 的核心入口函数,它彻底改变了 Vue 组件的组织方式,提供了更灵活的逻辑复用和代码组织能力。
setup() 的基本概念
作用
- 替代 Vue 2 的
data
、methods
、computed
等选项 - 作为组合式 API 的入口点
- 在组件创建之前执行,早于所有生命周期钩子
执行时机
- 在
beforeCreate
之前调用 - 此时组件实例尚未创建,无法访问
this
javascript
export default {
beforeCreate() {
console.log('1. beforeCreate');
},
setup() {
console.log('0. setup'); // 最先执行
},
created() {
console.log('2. created');
}
}
setup() 的参数
setup()
接收两个参数:
javascript
setup(props, context) {
// ...
}
props 参数
- 包含父组件传递的所有 prop
- 是响应式的,不能使用 ES6 解构(会失去响应性)
- 如果需要解构,使用
toRefs
javascript
import { toRefs } from 'vue'
export default {
props: ['title'],
setup(props) {
// ❌ 错误:直接解构会失去响应性
// const { title } = props;
// ✅ 正确:使用 toRefs 保持响应性
const { title } = toRefs(props)
console.log(title.value)
}
}
context 参数
包含三个有用的属性:
属性 | 描述 | 替代 Vue 2 的 |
---|---|---|
attrs | 非 prop 的 attribute | this.$attrs |
slots | 插槽内容 | this.$slots |
emit | 触发事件的方法 | this.$emit |
javascript
setup(props, { attrs, slots, emit }) {
// 访问非 prop 属性
console.log(attrs.class)
// 检查是否有插槽内容
if (slots.default) {
console.log('有默认插槽内容')
}
// 触发自定义事件
const handleClick = () => {
emit('change', '新值')
}
return { handleClick }
}
setup() 的返回值
setup()
返回的对象会:
- 暴露给模板使用
- 合并到组件实例中(可以通过
this
访问)
javascript
<template>
<div>{{ count }}</div>
<button @click="increment">+1</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => {
count.value++
}
return {
count,
increment
}
}
}
</script>
setup() 中使用生命周期钩子
在 setup()
中使用生命周期需要显式导入:
选项式 API | 组合式 API |
---|---|
beforeCreate | 不需要(直接在 setup 中写代码) |
created | 不需要(直接在 setup 中写代码) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
javascript
import { onMounted, onUpdated } from 'vue'
setup() {
onMounted(() => {
console.log('组件已挂载')
})
onUpdated(() => {
console.log('组件已更新')
})
}
<script setup>
语法糖
Vue 3.2+ 提供了更简洁的 <script setup>
语法:
html
<script setup>
import { ref } from 'vue'
// 变量自动暴露给模板
const count = ref(0)
// 函数自动暴露
const increment = () => {
count.value++
}
// 生命周期直接使用
import { onMounted } from 'vue'
onMounted(() => {
console.log('mounted')
})
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
<script setup>
的优势:
- 更少的样板代码
- 更好的 TypeScript 支持
- 更好的性能(编译时优化)
最佳实践
- 逻辑组织:将相关逻辑组织在一起(替代 Vue 2 的选项分割)
- 复用逻辑:将可复用的逻辑提取到 composable 函数中
- TypeScript:
<script setup>
提供更好的类型推断 - 避免
this
:在setup()
中永远不要使用this