外观
组合式API:setup()
基本用法
setup()
钩子在以下情况下作为组件中组合式API使用的入口点:
- 在不进行构建步骤的情况下使用组合式API;
- 将基于组合式API的代码集成到选项API组件中。
注意
如果您使用组合式API与单文件组件,强烈推荐使用 <script setup>
以获得更简洁、更直观的语法。
我们可以使用 响应性API 声明响应式状态,并通过从 setup()
返回一个对象将其暴露给模板。返回对象上的属性也将作为组件实例上的属性提供(如果使用了其他选项)
vue
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
// expose to template and other options API hooks
return {
count
}
},
mounted() {
console.log(this.count) // 0
}
}
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
从 setup
返回的 refs 在模板中访问时将自动浅解包,因此您在访问它们时不需要使用 .value
。当在 this
上访问时,它们也会以相同的方式解包。
setup()
本身无法访问组件实例 - 在 setup()
内部,this
的值将是 undefined
。您可以从选项API访问组合式API公开的值,但不能反向操作。
setup()
应该同步返回一个对象。唯一可以使用 async setup()
的情况是当组件是 Suspense 组件的子组件时。
访问属性
在 setup
函数中的第一个参数是 props
参数。正如您在标准组件中预期的那样,在 setup
函数内部的 props
是响应式的,并且当传入新的属性时将会更新。
js
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
请注意,如果您解构了 props
对象,解构的变量将失去响应性。因此,建议始终以 props.xxx
的形式访问属性。
如果您确实需要解构属性,或者需要在保持响应性的同时将属性传递给外部函数,可以使用 toRefs() 和 toRef() 工具 API 来实现。
js
import { toRefs, toRef } from 'vue'
export default {
setup(props) {
// turn `props` into an object of refs, then destructure
const { title } = toRefs(props)
// `title` is a ref that tracks `props.title`
console.log(title.value)
// OR, turn a single property on `props` into a ref
const title = toRef(props, 'title')
}
}
设置上下文
传递给 setup
函数的第二个参数是 设置上下文 对象。该上下文对象公开了在 setup
内可能有用的其他值。
js
export default {
setup(props, context) {
// Attributes (Non-reactive object, equivalent to $attrs)
console.log(context.attrs)
// Slots (Non-reactive object, equivalent to $slots)
console.log(context.slots)
// Emit events (Function, equivalent to $emit)
console.log(context.emit)
// Expose public properties (Function)
console.log(context.expose)
}
}
上下文对象不是响应式的,可以安全地解构。
js
export default {
setup(props, { attrs, slots, emit, expose }) {
...
}
}
attrs
和 slots
是状态对象,当组件本身更新时总是会被更新。这意味着您应该避免解构它们,并且始终以 attrs.x
或 slots.x
的形式引用属性。此外,与 props
不同,attrs
和 slots
的属性 不是 响应式的。如果您打算根据 attrs
或 slots
的更改应用副作用,您应该在 onBeforeUpdate
生命周期钩子内部这样做。
公开公共属性
expose
是一个函数,可以用来显式限制当组件实例通过 模板引用 由父组件访问时暴露的属性。
js
export default {
setup(props, { expose }) {
// make the instance "closed" -
// i.e. do not expose anything to the parent
expose()
const publicCount = ref(0)
const privateCount = ref(0)
// selectively expose local state
expose({ count: publicCount })
}
}
与渲染函数一起使用
setup
还可以返回一个 渲染函数,该函数可以直接使用同一作用域中声明的响应式状态。
js
import { h, ref } from 'vue'
export default {
setup() {
const count = ref(0)
return () => h('div', count.value)
}
}
返回渲染函数会阻止我们返回其他任何内容。从内部来看,这不应该是个问题,但如果我们想要通过模板引用将此组件的方法暴露给父组件,可能会出现问题。
我们可以通过调用 expose()
来解决这个问题。
js
import { h, ref } from 'vue'
export default {
setup(props, { expose }) {
const count = ref(0)
const increment = () => ++count.value
expose({
increment
})
return () => h('div', count.value)
}
}
然后,increment
方法将通过模板引用在父组件中可用。