前言
vue2
中有data、computed、method
等,我们有时候寻找一个变量或者函数就需要翻阅整段代码。vue3
提出了组合式API
,并且提出了可以使用组合式API
的地方—setup
。
<template>
<div>
<p>{{count}}</p>
<button @click="add">加1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'App',
setup(){
let count = ref(0);
function add(){
count.value += 1;
}
return { count, add };
}
}
</script>
setup
setup
组件选项在创建组件之前执行,此时尚未创建组件实例,所以setup
中并没有this
,所以在这里除了props
和context
的属性之外,都无法访问组件中声明的任何属性。
setup
接受 props
和 context
。
props
是响应式的,所以不能使用ES6
解构;context
有三个属性:context.attrs
、context.slots
和context.emit
,由于不是响应式的,所以可以解构
props: {
user: { type: String }
},
setup(props) {
console.log(props) // { user: '' }
return {} // 这里返回的任何内容都可以用于组件的其余部分
}
生命周期钩子
在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 |
提供/注入
在setup
中可以使用provider
和inject
:
import { provide } from 'vue';
// ...
setup(){
provide('username', 'sugarMei');
provide('geolocation', {
longitude: 90,
latitude: 135
})
}
import { inject } from 'vue';
// ...
setup() {
const userLocation = inject('username', 'The Universe') // 可以设置默认值
const userGeolocation = inject('geolocation')
return {
userLocation,
userGeolocation
}
}
给provider
和inject
提供响应式,确保(祖)父组件数据改变时,可以影响到子组件:
import { provide, reactive, ref } from 'vue'
// ...
setup(){
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
provide('location', location)
provide('geolocation', geolocation)
}
这样就OK了。
如果想要改变geolocation
,建议在提供的组件内部声明一个方法让其更改:
// (祖)父组件
methods: {
updateLocation() {
this.location = 'South Pole'
}
}
如果一定要在子组件更改的话, 在父组件注入这个方法,在子组件调用:
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', location)
provide('geolocation', geolocation)
provide('updateLocation', updateLocation)
}
// 子组件
import { inject } from 'vue'
export default {
setup() {
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')
const updateUserLocation = inject('updateLocation')
return {
userLocation,
userGeolocation,
updateUserLocation
}
}
}
如果想确保provide
传递的数据不会被注入的组件更改,可以使用readonly
:
provide('location', readonly(location))
provide('geolocation', readonly(geolocation))
getCurrentInstance
这个方法可以获得当前组件的实例,然后通过ctx
属性获得当前上下文,这样就可以在setup
中使用router
和vuex
了($router
和$store)
。
但是这个方法只能在setup
和生命周期中使用。
p.s. 在setup
中不能使用async
和await