setup() 是 Vue 3 组件选项 API 中的一个新选项。它是 Composition API 的入口点,在组件被创建之前执行,用于初始化状态、计算属性和方法,并返回在模板中使用的响应式引用。
setup 方法
为了开始使用组合式 API,我们首先需要一个可以实际使用它的地方。在Vue 3的组件中,我们将此位置称为setup方法,如示例代码所示。
<div id="app">
<component-b user="John" />
</div>
const componentB = {
props: {
user: {
type: String,
required: true
}
},
template:'<div></div>',
setup(props,context) {
console.log(props.user) // 打印'John'
return {} // 这里返回的任何内容都可以用于组件的其余部分
}
}
Vue.createApp({
components: {
'component-b': componentB
}
}).mount("#app")
setup方法参数
setup方法中接收两个参数,第一个参数式props,它和之前讲解组件通信中的props一样,可以接收到父组件传递的数据,同样,如果props是一个动态值,那么它就是响应式的,会随着父组件的改变而更新。
但是,因为props是响应式的,你不能使用ES6解构,它会消除prop的响应性。如果需要解构prop,可以在setup方法中使用toRefs函数来完成此操作,如下代码所示:
setup(props,context) {
const { user } = Vue.toRefs(props)
console.log(user.value) // 打印'John'
}
注意,如果是采用npm来管理的项目,可以采用如下import方式引入toRefs,包括后续的Composition API相关的方法:
import { toRefs } from 'vue'
如果user是可选的prop,则传入的props中可能没有user。在这种情况下,需要使用toRef替代它,代码如下:
setup(props,context) {
const { user } = Vue.toRef(props,'user')
console.log(user.value) // 打印'John'
}
setup方法的第二个参数是context对象,context是一个普通的JavaScript对象,它暴露组件的三个属性,分别是attrs,slots,emit,并且由于是普通的JavaScript对象,可以之间采用ES6解构,如示例代码所示。
<div id="app">
<component-b attrone="one" @emitcallback="emitcallback">
<template v-slot:slotone>
<span>slot</span>
</template>
</component>
</div>
const componentB = {
template:'<div></div>',
setup(props, { attrs, slots, emit }) {
// Attribute (非响应式对象)
console.log(attrs) // 打印 { attrone: 'one' } 相当于this.$attrs
// 插槽 (非响应式对象)
console.log(slots.slotone) // 打印{ slotone: function(){} } 相当于this.$slots
// 触发事件 (方法)
console.log(emit) // 可调用emit('emitcallback')相当于this.$emit
},
}
const vm = Vue.createApp({
components: {
'component-b': componentB
},
methods:{
emitcallback(){
console.log('emitcallback')
}
}
}).mount("#app")
其中,attrs对象是父组件传递给子组件且不在props中定义的的静态数据,它是非响应式的,相当于在没有使用setup方法时之外调用的this.$attrs效果。
slots对象主要是父组件传递的插槽内容,注意v-slot:slotone需要配置插槽名字,这样slots才能接收到,它是非响应式的,相当于在没有使用setup方法时之外调用的this.$slots效果。
emit对象主要用来和父组件通信,相当于在没有使用setup方法时之外调用的this.$emit效果。
setup方法结合模板使用
如果setup方法返回一个对象,那么该对象的属性以及传递给setup的props参数中的属性就都可以在模板template中访问到,如示例代码所示。
<div id="app">
<component-b user="John" />
</div>
const componentB = {
props: {
user: {
type: String,
required: true
}
},
template:'<div>{{user}} {{person.name}}</div>',
setup(props) {
const person = Vue.reactive({ name: 'Son' })
// 暴露给 template
return {
person
}
},
}
Vue.createApp({
components: {
'component-b': componentB
}
}).mount("#app")
注意,props中的数据我们不必在setup中返回,Vue会自动的暴露给模板template中使用。