组合式API
在Vue2中,一个组件通通包含data、computed、methods、watch等组件选项来组织逻辑,当组件变得越来越大时,逻辑关注点的列表也会增长,尤其对于那些一开始没有编写这些组件的人来说,这会导致组件难以阅读和理解。
这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。
如果能够将同一个逻辑关注点相关代码收集在一起会更好。而这正是组合式 API 使我们能够做到的。
因此,Vue3引入了 setup 组件选项,用于实现组合式API。
setup在生命周期的位置
setup位于beforeCreate和created之前,用于替代两者,在组件创建之前执行,一旦props被解析,就将作为组合式API的入口
此外,可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。
下表包含如何在setup()内部调用生命周期钩子:
| 选项式 API | Hook inside setup |
|---|---|
beforeCreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
activated | onActivated |
deactivated | onDeactivated |
export default {
setup() {
// mounted
onMounted(() => {
console.log('Component is mounted!')
})
}
}
this
在setup()内部,this指向的不是vue实例,因为setup()是在解析其他组件选项之前被调用的。所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同。这使得 setup() 在和其它选项式 API 一起使用时可能会导致混淆。
setup参数
setup()接收两个参数
propscontext
props
setup 函数中的第一个参数是 props。props 是响应式的,当传入新的 prop 时,它将被更新。
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
但是,因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。
如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作:
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。你需要使用 toRef 替代它:
import { toRef } from 'vue'
setup(props) {
const title = toRef(props, 'title')
console.log(title.value)
}
context
传递给 setup 函数的第二个参数是 context。context 是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值:
export default {
setup(props, context) {
// Attribute (非响应式对象,等同于 $attrs)
console.log(context.attrs)
// 插槽 (非响应式对象,等同于 $slots)
console.log(context.slots)
// 触发事件 (方法,等同于 $emit)
console.log(context.emit)
// 暴露公共 property (函数)
console.log(context.expose)
}
}
context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构。
export default {
setup(props, { attrs, slots, emit, expose }) {
...
}
}
访问组件的property
执行 setup 时,你只能访问以下 property:
propsattrsslotsemit
换句话说,你将无法访问以下组件选项:
datacomputedmethodsrefs(模板 ref)\
结合模板使用
setup()必须返回一个对象,一旦return,就可以像vue2的方式那样使用该属性
<template>
<div>{{ collectionName }}: {{ readersNumber }} {{ book.title }}</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
props: {
collectionName: String
},
setup(props) {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
// 暴露给 template
return {
readersNumber,
book
}
}
}
</script>
组件选项返回优先级
如果data,props,setup都有一个同名属性,setup返回的该属性优先级最高.
如何调用子组件setup内的方法
-
子组件在
setup写好方法method,并通过return暴露出去 -
父组件调用子组件时为其添加
ref属性 -
父组件
setup内拿到(2)添加的ref属性property,再通过property.value.method()调用子组件