setup 内部无法使用 this
首先我们知道,Vue3 的组合式 API 关键点就在入口函数 setup 的使用上。而在 setup() 内部,this 不是该活跃实例的引用,因为 setup() 是在解析其它组件选项之前被调用的,所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同。这使得 setup 内部并不能访问到 组件实例的 this,很多 Vue2 以来的习惯语法都要进行重新更改了。
setup 可访问组件的 property
执行 setup 时,只能访问以下 property:
propsattrsslotsemit
换句话说,将无法访问以下组件选项:
datacomputedmethodsrefs(模板 ref)
property 在模板中使用
如果 setup 返回一个对象,那么该对象的 property 以及传递给 setup 的 props 参数中的 property 就都可以在模板中访问到:
<template>
<div>{{ name }}: {{ age }} {{ book.title }}</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
props: {
name: String
},
setup(props) {
const age = ref(0)
const book = reactive({ title: 'novel' })
// 把 props 暴露给 template
return {
age,
book
}
}
}
</script>
注意,从 setup 返回的 ref 响应式变量虽然是对象类型,但在模板中访问时是被自动浅解包的,因此不应在模板中添加额外的 .value,否则会报错。
通常使用 ref 来存储基本类型的变量,而用 reactive 来存储对象类型、数组等变量。
使用渲染函数
setup 还可以返回一个渲染函数,该函数可以直接使用响应式状态:
<template>...</template>
<script>
import { h, ref, reactive } from 'vue'
export default {
setup() {
const age = ref(0)
const book = reactive({ title: 'novel' })
// 注意在 script 部分需要显式使用 ref 的 value
return () => h('div', [age.value, book.title])
}
}
</script>
返回一个渲染函数将阻止我们返回任何其它的变量、方法等等。对于该组件内部来说没有问题,但当我们想要将这个组件的方法通过模板 ref 暴露给父组件时就不一样了。
如果有这种需求,可以通过调用 expose 来解决这个问题,给它传递一个对象,其中定义的 property 将可以被外部组件实例访问,例如:
import { h, ref } from 'vue'
export default {
setup(props, { expose }) {
const count = ref(0)
const add = () => ++count.value
expose({
add
})
return () => h('div', count.value)
}
}
传递的 attribute 默认绑定组件根元素
这里需要提到一个重要参数,inheritAttrs :
-
类型:
boolean -
默认值:
true
默认情况下父组件的不被识别作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。如果这一默认操作不符合项目搭建预期。需要通过设置 inheritAttrs 到 false,从而取消这些默认行为。而通过 (2.4 新增的) 实例 property $attrs 可以让这些 attribute 生效,并使用 v-bind 显性的绑定到非根元素上。
此外这个选项不影响 class 和 style 绑定。
生命周期钩子函数
在 setup 里,你可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。
下表详细列举了如何在 setup () 内部调用生命周期钩子:
| 选项式 API | Hook inside setup |
|---|---|
beforeCreate | 不需要 |
created | 不需要 |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
activated | onActivated |
deactivated | onDeactivated |
需要注意的是,beforeCreate 和 created 两个生命周期钩子不需要在setup里定义,因为 setup 本身是围绕 beforeCreate 和 created 两个生命周期运行的,所以不需要显式地定义它们。在这两个钩子中编写的任何代码直接在 setup 函数中编写即可。
例如 mounted 钩子如下:
export default {
setup() {
onMounted(() => {
console.log('mounted')
})
}
}