组合式API
setup()
作用:在组件中使用组合式API的入口。
使用情景:1. 在非单文件组件中使用组合式API时。2. 在基于选项式API的组件中集成基于组合式API的代码时。
注意事项:在单文件组件中使用组合式API,推荐使用
<script setup>
功能:在 setup() 函数中返回的对象,模板和其它API可以直接使用。
<script>
import {ref} from 'vue'
export default {
setup() {
const count = ref(0)
return {
count
}
},
// 可以使用,通过 this. 获取
mounted() {
console.log(this.count)
}
}
</script>
<template>
// 可以使用,直接获取
<button @click="count++">
{{count}}
</button>
</template>
注意:在模板中访问从 setup 返回的 ref 时,会自动浅层解包,不用写 .vaule。在 setup 中访问 this 为 undefined,没有对组件实例的访问权,可以在选项式API中访问组合式API暴露的值,反之不可以。setup 应该同步的返回一个对象,在 Suspense 组件的后裔中可以使用异步。
参数:setup() 的第一个参数是组件的 props,是响应式且同步更新的。
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
注意:解构 props 会失去响应性,推荐使用 props.xxx 的形式。如果必须要解构,可以使用
toRefs()
和toRef()
这两个工具函数。
import {toRefs, toRef} from 'vue'
export default {
props: {
title: String
},
setup(props) {
// 使用 toRefs 将 props 转为全是 ref 的对象,然后解构
const {title} = toRefs(props)
// 需要使用 .value
console.log(title.value)
// 或者使用 toRef 将 props 某一个属性转为 ref
const title1 = toRef(props, 'title')
}
}
参数:setup 的第二个参数是一个 Setup 上下文对象, 暴露了其他一些在 setup
中可能会用到的值。是非响应式的,可以直接解构。
export default {
setup(props, context) {
// 透传 Attributes(非响应式的对象,等价于 $attrs)
console.log(context.attrs)
// 插槽(非响应式的对象,等价于 $slots)
console.log(context.slots)
// 触发事件(函数,等价于 $emit)
console.log(context.emit)
// 暴露公共属性(函数)
console.log(context.expose)
}
}
// 直接解构
export default {
setup(props, { attrs, slots, emit, expose }) {
...
}
}
注意:
attrs
和slots
都是有状态的对象,它们总是会随着组件自身的更新而更新。应该避免解构,使用时通过 attrs.xxx 调用。 和props
不同,attrs
和slots
的属性都不是响应式的。如果你想要基于attrs
或slots
的改变来执行副作用,那么你应该在onBeforeUpdate
生命周期钩子中编写相关逻辑。
expose 函数的作用: 用于显式地限制该组件暴露出的属性,当父组件通过模板引用访问该组件的实例时,将仅能访问 expose
函数暴露出的内容。
export default {
setup(props, { expose }) {
// 让组件实例处于 “关闭状态”
// 即不向父组件暴露任何东西
expose()
const publicCount = ref(0)
const privateCount = ref(0)
// 有选择地暴露局部状态
expose({ count: publicCount })
}
}
expose 函数的使用场景之一:当 setup 返回一个渲染函数,且想暴露一些方法给父组件时,可以结合 expose 函数来使用。
setup
也可以返回一个渲染函数,此时在渲染函数中可以直接使用在同一作用域下声明的响应式状态。返回一个渲染函数将会阻止我们返回其他东西。对于组件内部来说,这样没有问题,但如果我们想通过模板引用将这个组件的方法暴露给父组件,我们可以通过调用expose()
解决这个问题。
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
方法。