什么是组合式API
组合式 API(Composition API)是一系列 API 的集合,使我们可以使用函数而不是声明选项的方式书写 Vue 组件。它是一个概括性的术语,涵盖了以下方面的 API:
- 响应式 API (opens new window):使我们可以直接创建响应式状态、计算属性和侦听器,如:
ref()
和reactive()
- 生命周期钩子 (opens new window):使我们可以在组件各个生命周期阶段添加逻辑,如:
onMounted()
和onUnmounted()
- 依赖注入 (opens new window):使我们可以在使用响应式 API 时,利用 Vue 的依赖注入系统,如
provide()
和inject()
在最新的vue中,vue采用了组合式API的风格来书写代码,vue官方展示了组合式API和选择式API的用法
选项式 API (Options API)
使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 data、methods 和 mounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。
javascript
<script>
export default {
// data() 返回的属性将会成为响应式的状态
// 并且暴露在 `this` 上
data() {
return {
count: 0
}
},
// methods 是一些用来更改状态与触发更新的函数
// 它们可以在模板中作为事件处理器绑定
methods: {
increment() {
this.count++
}
},
// 生命周期钩子会在组件生命周期的各个不同阶段被调用
// 例如这个函数就会在组件挂载完成后被调用
mounted() {
console.log(`The initial count is ${this.count}.`)
}
}
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
组合式 API (Composition API)
通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup
attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup>
中的导入和顶层变量/函数都能够在模板中直接使用。
下面是使用了组合式 API 与 <script setup>
改造后和上面的模板完全一样的组件:
javascript
<script setup>
import { ref, onMounted } from 'vue'
// 响应式状态
const count = ref(0)
// 用来修改状态、触发更新的函数
function increment() {
count.value++
}
// 生命周期钩子
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
可以发现这两个代码书写方式的不同点在于组合式API的script标签多了一个setup属性,同时多了一个ref方法。
这里的setup属性其实是对setup函数的一个封装,它表示整个script标签的内容全部都属于setup函数,并自动返回响应式的值。
setup函数和script setup标签
setup函数
setup()
函数返回值通常是一个对象,这个对象的所有属性会暴露给组件模板和组件实例setup()
函数中的this
指向undefined
setup()
函数会在所有生命周期函数beforeCreate
之前被执行。setup()
函数内定义的变量默认为非响应式的,所以对外暴露该属性为非响应式
html
<script>
export default {
// setup函数是所有组合式API的入口(表演的舞台)
setup() {
// .....所有代码在此书写
},
};
</script>
在setup函数中返回的对象属性,在整个组件中是直接可以被访问的,但是这些属性都是非响应性的,当改变属性的值时,页面并不会同步更新,非响应的值对组件来说相当于一个常量,无法改变 ,,那我们知道vue框架是一个动态可编辑的组件集合,这自然是需要能响应的值来保证其动态更新,这就需要使用响应式API来实现
什么是响应式API
在setup函数中,返回的值是不能够被改变的,通过响应式API(ref和reactive)的响应式代理,可以实现传递动态变化的值。
ref方法
接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value
- 可更改是指你可以为
ref
对象的value
属性赋予新的值 - 响应式是指所有对
.value
的操作都将被追踪,并且写操作会触发与之相关的副作用(DOM 更新)
html
<script>
import { ref } from "vue";
export default {
setup() {
// msg为一个ref对象,并且是响应式的
const msg = ref("Hello Vue!!"); // {value: "Hello Vue!!"}
// 修改ref对象value属性的值
msg.value = "Hello ref!!";
return {
msg,
};
},
};
</script>
<template> {{ msg }} </template>
使用setup的script标签
html
<script setup>
import { ref } from "vue";
// msg为一个ref对象,并且是响应式的
const msg = ref("Hello Vue!!"); // {value: "Hello Vue!!"}
// 修改ref对象value属性的值
msg.value = "Hello ref!!";
</script>
<template> {{ msg }} </template>

这里的msg其实就相当于一个对象他有一个属性value,值等于注入的值,例如,字符串,数字,对象,可以通过value属性来访问到这个值,
但是我们注意到,既然这个值是在value属性中存放的,在template标签又直接使用msg却打印出了值,这里是响应式对象会自动解包 ref 属性。
一个响应式对象的属性及嵌套属性的值如果为ref
属性,在模板或setup()
中使用时,会自动解包,同时保持响应性(msg = msg.value),但是,当访问到某个响应式数组或 Map
这样的原生集合类型中的 ref
元素时,不会执行 ref 的解包。同时,在script标签内是不会解包的,任需要通过value来访问值。
reactive方法
reactive()
方法用来返回一个对象的响应式代理(对象)。
javascript
const objProxy = reactive(obj); // objProxy为obj对象的响应式代理
html
<script>
// 导入reactive方法
import { reactive } from "vue";
export default {
setup() {
const obj = { a: 1, b: 2 };
// Info为响应式代理对象
const objProxy = reactive(obj);
console.log(objProxy); // Proxy(Object) {a: 1, b: 2}
function update() {
// 修改对象属性的值
objProxy.a = 10;
objProxy.b = 20;
}
// 将属性暴露给组件实例
return {
objProxy,
update,
};
},
};
</script>
<template>
<div>a的值:{{ objProxy.a }}</div>
<div>b的值:{{ objProxy.b }}</div>
<button @click="update">更新a,b的值</button>
</template>

点击按钮后a,b的值改变并渲染到了页面上,这表示objProxy
代理对象具有响应性,所以objProxy
为响应式代理对象。
但是要注意reactive() 无法转换基本数据类型,
javascript
const msg = reactive("Hello Vue!!");// error
这种用法会直接报错,reactive()
方法只能将一个对象转换为一个响应式对象,而不能将一个基本数据类型转换为响应式对象。因为reactive()
方法的底层采用的是Proxy
来实现的,而Proxy
只能创建对象的代理。Proxy对象可以参考: Proxy - JavaScript | MDN
正确的方式是使用ref
javascript
const msg = ref("Hello Vue!!");// success
总结
响应式API可以让setup中的非响应数据,传递出来,并使其可以响应,从而实现页面的动态编辑,
我们可以把ref和reactive看成组件中对数据的特殊赋值,
javascript
const num = ref(0); => let num = 0;
const obj = reactive({age:10}); => let obj = {name:10};
更多相关内容可以参考:
Vue 组合式 API - setup、reactive 与 ref,响应式工具 | arry老师的博客-艾编程 (arryblog.com)