Vue3.0带来了一个全新的特性(Composition API),字面意思就是“组合 API”,它是为了实现基于函数的逻辑复用机制而产生的。
在了解Composition Api之前,首先回顾下我们在Vue2中使用Option Api遇到的问题,我们在Vue2中常常会需要在特定的区域(data,methods,watch,computed…)编写负责相同功能的代码。
随着业务复杂度越来越高,代码量会不断的加大;由于相关业务的代码需要遵循option的配置写到特定的区域,导致后续维护非常的复杂,代码可复用性也不高。
即相同的功能函数写了多个,复用性不高,当代码量以及项目越来越大时,不好维护。
Composition API在Vue 3中开箱即用,如果想在Vue 2中使用Composition API,可以在项目中添加@vue/composition-api插件.
从图中可以看出来,composition api会把相同或类似功能的函数代码放在一起。
- 值类型(即基本数据类型)无处不在,如果不用 ref 而直接返回值类型,会丢失响应式
- 比如在 setup 、 computed 、合成函数等各种场景中,都有可能返回值类型
- Vue 如果不定义 ref ,用户将自己制造 ref ,这样反而会更加混乱
ref需要通过.value来修改值
- ref 是一个对象,这个对象不丢失响应式,且这个对象用 value 来存储值
- 通过 .value 属性的 get 和 set 来实现响应式
- 当用于 模板 和 reactive 时,不需要 .value 来实现响应式,而其他情况则都需要
ref demo {{ageRef}} {{state.name}}
// 输出结果:
ref demo 18 monday // 响应式前的数据
ref demo 20 mondaylab // 响应式后的数据
ref可以实现值类型的数据响应式
今天是周一
// 输出结果
ref template 今天是周一
今天是周一
通过在模板中绑定一个 ref ,之后在生命周期中调用,最后浏览器显示出该DOM元素。即ref 也可以用来渲染模板中的DOM元素
对一个普通对象来说,如果这个普通对象要实现响应式,就用reactive。用了reactive后,它就是一个响应式对象。那么在 一个响应式对象里面,如果其中有一个属性要拿出来单独做响应式的话,就可以用toRef。
toRef(Object, prop) 的形式来传对象名和具体的属性名,达到某个属性数据响应式的效果。
toRef demo - {{ageRef}} - {{state.name}} {{state.age}}
// 输出结果:
toRef demo - 18 - monday 18
toRef demo - 20 - monday 20
toRef demo - 25 - monday 25
toRefs demo {{age}} {{name}}
// 输出结果
age 18 name monday
age 20 name 周一
toRef和toRefs这两个兄弟,它们不创造响应式,而是延续响应式。创造响应式一般由ref或者reactive来解决,而toRef和toRefs则是把对象的数据进行分解和扩散,其这个对象针对的是响应式对象而非普通对象。
- 在不丢失响应式的情况下,把对象数据进行分解或扩散
- 针对的是响应式对象( reactrive 封装的)而非普通对象
- 不创造响应式,而是延续响应式
function fn(){
const state = reactive({
x: 1,
y: 2
})
// TODO 代码逻辑
return toRefs(state) // 用toRefs将state对象进行返回
}
export default{
setup(){
const {x, y} = fn() // 组件里面直接调用响应式对象
return{
x,
y
}
}}
// 模版代码
Spaces left: {{ spacesLeft }} out of {{ capacity }}
Attending
{{ item }}
// 通过vue3中setup实现上述功能
// 引入ref和computed
import { ref, computed } from "vue"
setup() {
const capacity = ref(4)
const attending = ref(["Tim", "Bob", "Joe"])
// computed计算属性的声明方式
const spacesLeft = computed(() => {
// 注意,通过ref声明的响应式数据需要通过.value拿到该值
return capacity.value - attending.value.length
})
// 代替methods声明方法
function increaseCapacity () {
capacity.value++
}
function sort () {
attending.value = lodash.shuffle(attending.value)
}
function addAttending () {
attending.value.push(lodash.random(3, 7))
}
// 通过一个对象暴露以上变量和方法
return {
capacity,
attending,
spacesLeft,
increaseCapacity,
sort,
addAttending
}
}
// 将需要使用的变量添加到event的属性中
setup(props, context) {
console.log(props)
// Attributes (Non-reactive object)
console.log(context.attrs)
// Slots (Non-reactive object)
console.log(context.slots)
// Emit Events (Method)
console.log(context.emit)
const event = reactive({
capacity: 4,
attending: ['Tim', 'Bob', 'Joe'],
spacesLeft: computed(() => { return event.capacity - event.attending.length })
})
// 方法的声明方法不变
function increaseCapacity () {
event.capacity++
}
function sort () {
event.attending = lodash.shuffle(event.attending)
}
function addAttending () {
event.attending.push(lodash.random(3, 7))
}
// toRefs()
return {...toRefs(event), increaseCapacity, addAttending, sort}
},
接受2个参数,第一个参数props,就是Vue的props。setup()执行时还没有vue实例,所以在setup()函数体内拿不到data、computed和methods,所以需要借助第二个参数context拿到vue实例相关的数据,其中包含attrs、slots和emit。
setup()内部有相应的vue生命周期hooks供开发者使用,具体可以参考官方文档。
我们来对比打印一下新旧两版生命周期hooks:
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onUnmounted
} from "vue"
function printLifeCycle () {
onBeforeMount(() => {console.log('onBeforeMount')})
onBeforeUpdate(() => {console.log('onBeforeUpdate')})
onMounted(() => {console.log('onMounted')})
onUpdated(() => {console.log('onUpdated')})
onUnmounted(() => {console.log('onUnmounted')})
}
export default {
// setup内部生命周期hooks
setup(props, context) {
printLifeCycle()
},
// 老生命周期hooks
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
}
}
setup()内部的hooks执行早于vue实例上的老hooks
参考网址:
https://juejin.cn/post/6890545920883032071(简单的动画,清楚的描述,通俗易懂)
https://juejin.cn/post/6976679225239535629#heading-9