# 组合式 API
本节例子中代码使用的单文件组件语法
# setup
一个组件选项,在组件被创建之前,props
被解析之后执行。它是组合式 API 的入口。
入参:
{Data} props
{SetupContext} context
与使用选项式 API 时的
this.$props
类似,该props
对象将仅包含显性声明的 prop。并且,所有声明了的 prop,不管父组件是否向其传递了,都将出现在props
对象中。其中未被传入的可选的 prop 的值会是undefined
。如果需要检测一个可选的 prop 是否未被传递,你可以将其默认值设置为一个 Symbol:
const isAbsent = Symbol() export default { props: { foo: { default: isAbsent } }, setup(props) { if (props.foo === isAbsent) { // foo 没有被传入。 } } }
1
2
3
4
5
6
7
8
9
10
11类型声明:
interface Data { [key: string]: unknown } interface SetupContext { attrs: Data slots: Slots emit: (event: string, ...args: unknown[]) => void expose: (exposed?: Record<string, any>) => void } function setup(props: Data, context: SetupContext): Data
1
2
3
4
5
6
7
8
9
10
11
12TIP
若要对传递给
setup()
的参数进行类型推断,你需要使用 defineComponent。示例:
使用模板:
<!-- MyBook.vue --> <template> <div>{{ readersNumber }} {{ book.title }}</div> </template> <script> import { ref, reactive } from 'vue' export default { setup() { const readersNumber = ref(0) const book = reactive({ title: 'Vue 3 Guide' }) // 暴露给模板 return { readersNumber, book } } } </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21使用渲染函数:
// MyBook.vue import { h, ref, reactive } from 'vue' export default { setup() { const readersNumber = ref(0) const book = reactive({ title: 'Vue 3 Guide' }) // 请注意,我们需要在这里显式地使用 ref 值 return () => h('div', [readersNumber.value, book.title]) } }
1
2
3
4
5
6
7
8
9
10
11
12如果返回了渲染函数,则不能再返回其他 property。如果需要将 property 暴露给外部访问,比如通过父组件的
ref
,可以使用expose
:// MyBook.vue import { h } from 'vue' export default { setup(props, { expose }) { const reset = () => { // 某些重置逻辑 } // expose 只能被调用一次。 // 如果需要暴露多个 property,则它们 // 必须全部包含在传递给 expose 的对象中。 expose({ reset }) return () => h('div') } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 生命周期钩子
可以通过直接导入 onX
函数来注册生命周期钩子:
import { onMounted, onUpdated, onUnmounted } from 'vue'
const MyComponent = {
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这些生命周期钩子注册函数只能在 setup()
期间同步使用,因为它们依赖于内部的全局状态来定位当前活动的实例 (此时正在调用其 setup()
的组件实例)。在没有当前活动实例的情况下,调用它们将会出错。
组件实例的上下文也是在生命周期钩子的同步执行期间设置的,因此,在生命周期钩子内同步创建的侦听器和计算属性也会在组件卸载时自动删除。
选项式 API 的生命周期选项和组合式 API 之间的映射
-> 使用beforeCreate
setup()
-> 使用created
setup()
beforeMount
->onBeforeMount
mounted
->onMounted
beforeUpdate
->onBeforeUpdate
updated
->onUpdated
beforeUnmount
->onBeforeUnmount
unmounted
->onUnmounted
errorCaptured
->onErrorCaptured
renderTracked
->onRenderTracked
renderTriggered
->onRenderTriggered
activated
->onActivated
deactivated
->onDeactivated
# Provide / Inject
provide
和 inject
启用依赖注入。这两者只能在使用当前活动实例的 setup()
期间被调用。
类型声明:
interface InjectionKey<T> extends Symbol {} function provide<T>(key: InjectionKey<T> | string, value: T): void // 没有默认值 function inject<T>(key: InjectionKey<T> | string): T | undefined // 有默认值 function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T // 有工厂函数 function inject<T>( key: InjectionKey<T> | string, defaultValue: () => T, treatDefaultAsFactory: true ): T
1
2
3
4
5
6
7
8
9
10
11
12
13
14Vue 提供了一个
InjectionKey
接口,该接口是扩展了Symbol
的泛型类型。它可用于在生产者和消费者之间同步 inject 值的类型:import { InjectionKey, provide, inject } from 'vue' const key: InjectionKey<string> = Symbol() provide(key, 'foo') // 若提供非字符串值将出错 const foo = inject(key) // foo 的类型: string | undefined
1
2
3
4
5
6
7如果使用了字符串 key 或非类型化的 symbol,则需要显式声明 inject 值的类型:
const foo = inject<string>('foo') // string | undefined
1参考:
# getCurrentInstance
getCurrentInstance
支持访问内部组件实例。
WARNING
getCurrentInstance
只暴露给高阶使用场景,典型的比如在库中。强烈反对在应用的代码中使用 getCurrentInstance
。请不要把它当作在组合式 API 中获取 this
的替代方案来使用。
import { getCurrentInstance } from 'vue'
const MyComponent = {
setup() {
const internalInstance = getCurrentInstance()
internalInstance.appContext.config.globalProperties // 访问 globalProperties
}
}
2
3
4
5
6
7
8
9
getCurrentInstance
只能在 setup 或生命周期钩子中调用。
如需在 setup 或生命周期钩子外使用,请先在
setup
中调用getCurrentInstance()
获取该实例然后再使用。
const MyComponent = {
setup() {
const internalInstance = getCurrentInstance() // 有效
const id = useComponentId() // 有效
const handleClick = () => {
getCurrentInstance() // 无效
useComponentId() // 无效
internalInstance // 有效
}
onMounted(() => {
getCurrentInstance() // 有效
})
return () =>
h(
'button',
{
onClick: handleClick
},
`uid: ${id}`
)
}
}
// 在组合式函数中调用也可以正常执行
function useComponentId() {
return getCurrentInstance().uid
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
← Effect 作用域 API 规范 →