VUE3 组合式API理解
什么是组合式 API
以前的vue2是选项式API,代码一多就容易乱,数据、方法、计算属性的混在一起,找起来都费劲。
组合式API就好比把东西都分门别类放好,想看数据处理的就看setup里相关的部分,想看方法就找对应的方法函数,一目了然,自己写代码的时候思路也更清晰,别人看代码也更容易懂。
在选项式API里,想在多个组件复用一段逻辑,得把公共部分抽成方法,但这种方式比较粗,不够灵活。比如你有个用户信息处理的逻辑,涉及好几个属性和方法,用选项式API就不太好整体复用。
组合式API就能把相关逻辑封装成一个函数,这个函数里啥都有,数据、方法、计算属性啥的,然后在多个组件里直接调用这个函数就行,复用起来贼方便,就像搭积木一样,把需要的功能模块往组件里一放就成。这一点是极大提升开发效率的,同时组合式API对于用TypeScript开发的项目简直就是福音。所以理解组合式API是现代前端开发的必不可少的
选项式 API 是按照 data、methods、computed 等模块化的方式来写代码。
export default {
data() {
return { count: 0 };
},
methods: {
increment() {
this.count++;
}
}
};
组合式 API 是把所有逻辑和状态写在一起,用函数组织代码。
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
}
};
组合式 API 的核心概念 setup
函数和响应式 API
在 Vue 3 中,setup
函数是 Composition API 的核心,它用于组件的逻辑组织,而不再是像 Vue 2 中那样通过 data
、methods
和 computed
来定义。setup
函数被设计用来组织组件的状态和行为,因此,响应式 API 是必不可少的。
setup
函数中的代码会在组件实例化之前执行,并且是响应式的逻辑所在。你可以在 setup
中使用 reactive
、ref
、computed
和 watch
来定义组件的状态,并处理副作用。
import { reactive, ref, computed } from 'vue';
export default {
setup() {
const count = ref(0);
const state = reactive({ name: 'Vue 3', count: 0 });
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, state, doubleCount, increment };
}
};
count
使用ref
创建了一个响应式的数字变量。state
使用reactive
创建了一个响应式对象。doubleCount
使用computed
创建了一个计算属性,它依赖count
,只有count
改变时doubleCount
才会重新计算。increment
是一个方法,修改了count。
setup
函数的返回值会暴露给模板。在模板中,你可以直接使用 count
、state``、doubleCount
和 increment
,它们都是响应式的。 Vue 会根据这些响应式数据的变化自动更新视图。
<script setup>
语法糖
Vue 3 引入了 <script setup>
作为 Composition API 的一种语法糖,极大地简化了 setup 的写法,并且提高了代码的可读性和简洁性。使用 <script setup>
,你不需要显式地写 setup()
函数,也不需要 return
来暴露变量和方法。它自动将所有导入的模块和定义的响应式状态暴露到模板中。
你只需在 <script>
标签上加上 setup 属性,就能开启 Vue 3 的语法糖。这样写会让你的代码更加简洁,直接将响应式变量和方法暴露给模板。
<script setup>
import { ref, computed } from 'vue';
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
</script>
<template>
<div>
<p>{{ count }}</p>
<p>{{ doubleCount }}</p>
<button @click="increment">Increase</button>
</div>
</template>
在这个例子中,count
、doubleCount
和 increment
会自动暴露到模板中,你可以直接使用它们,而无需 return。这使得代码看起来更简洁、更直观
setup 与 <script setup>
的区别
setup
函数: 你需要显式地使用setup
函数,并且必须通过return
将状态和方法暴露到模板中。<script setup>
: 这种语法糖自动暴露所有的变量和方法,简化了代码结构。
<script setup>
更加简洁,没有多余的 return 语句,且没有 export default,直接以 <script setup>
开头就能使用 Vue 3 的 Composition API。
响应式数据:ref
和 reactive
Vue 3 提供了两种方式来定义响应式数据:ref 和 reactive。
reactive
用来创建响应式对象
reactive
用于创建一个响应式的对象。通过这个 API,你可以把一个普通的对象变成 Vue 3 响应式系统管理的对象。这个对象的所有属性都将变成响应式的,即当你改变这些属性时,Vue 会自动重新渲染相关的组件。
import { reactive } from 'vue';
const state = reactive({
count: 0,
name: 'Vue 3'
});
state.count++; // 改变 count 的值,视图会自动更新
state.name = 'Vue 3 - 响应式'; // 改变 name 的值,视图会自动更新
在这个例子中,创建了一个 state
对象,并将它通过 reactive
转换成响应式对象。当你修改 state
对象的属性时,Vue 会自动检测到变化并更新视图。
reactive
只适用于对象(包括数组),不能用于基本数据类型(如字符串、数字、布尔值)。 如果你对一个对象中的嵌套属性进行修改,嵌套的属性也会自动变成响应式的。
嵌套对象的响应式:
const person = reactive({
name: 'Simin',
address: {
city: 'changsha'
}
});
person.address.city = 'shanghai'; // 这个变更也会自动更新视图
ref
:适合简单数据(如数字、字符串等)
ref
用来创建单个变量的响应式数据。它会把值包裹在一个对象中,数据要通过 .value
来访问。
ref 用来创建响应式的基本数据类型。与 reactive 不同,ref 是为了处理原始数据类型(如字符串、数字、布尔值、null、undefined等)。它的作用是将这些基本数据类型包装成一个对象,这个对象包含一个 .value 属性,通过这个属性访问和修改值。
import { ref } from 'vue';
const count = ref(0);
count.value++; // 通过 .value 来修改数据
count
是一个响应式的数字,修改它的值时必须通过 .value
来访问和更新。
ref
创建的变量是一个对象,Vue 需要通过.value
来跟踪它的变化。- 对于基本数据类型,不能直接访问和修改变量本身,必须通过
.value
。 ref
也可以用来包装对象,这时候你仍然可以通过.value
访问对象。
对象类型的 ref
:
const person = ref({
name: 'Simin',
age: 25
});
person.value.name = '_SImin_'; // 通过 .value 修改对象的属性
reactive 和 ref 的区别
reactive
用来处理对象,自动将对象的每个属性都变成响应式。ref
主要用于原始数据类型,并通过.value
来访问数据。- 你也可以将对象包装成
ref
,但通常如果你处理的是复杂的对象或数组,使用reactive
会更方便。
计算属性:computed
什么是计算属性
computed
是一种声明式的方法,用来定义依赖于其他变量的值。它类似于函数,但具有缓存特性:只有依赖的值变化时才会重新计算。 计算属性就是一种特殊的属性,它可以根据组件里的其他数据来计算出一个新的值。有点像你在Excel里,根据几个单元格的数据,用公式算出一个新的结果。
为什么需要计算属性
想象一下,你有个用户的名字和姓氏,分别存储在两个数据属性里,比如firstName和lastName。现在你想在页面上显示用户的全名。如果没有计算属性,你可能得在模板里写 ,这样虽然也能显示全名,但每次只要firstName或lastName变化,你都得重新拼接一次,有点麻烦。
有了计算属性,你就可以定义一个叫fullName的计算属性,它自动根据firstName和lastName的值来计算全名。这样,不管firstName还是lastName变化,fullName都能自动更新,你直接在模板里用就行,代码更简洁,也更容易维护。
import { ref, computed } from 'vue';
export default {
setup() {
const firstName = ref("小");
const lastName = ref("明");
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`;
});
return { firstName, lastName, fullName };
}
};
<template>
<div>
<p>全名:{{ fullName }}</p>
</div>
</template>
详细解释:
firstName
和 lastName
是响应式变量,初始值分别为 "小" 和 "明"。
fullName
是一个计算属性,依赖于 firstName
和 lastName
,当它们的值发生变化时,fullName
会自动重新计算。 在模板中使用 时,不需要显式调用函数,Vue 会自动计算并渲染结果。
computed
是只读的,不能直接修改其值。如果需要可写的计算属性,可以通过 getter
和 setter
实现:
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (newValue) => {
const names = newValue.split(" ");
firstName.value = names[0];
lastName.value = names[1];
}
});
监视器 watch
什么是监视器
watch就像是个“小侦探”,专门盯着Vue里的数据,只要数据一有变化,它就能立刻发现,然后执行你提前设定好的操作。有点像你让一个小伙伴看着你的玩具,一旦玩具被别人动了,他就马上告诉你。
为什么需要watch
有时候,我们希望在数据变化时做一些事儿。比如,你有个输入框,用户在里面输入内容,你希望根据输入的内容去搜索数据库。这种时候,就可以用watch来监听输入框的内容,内容一变,就触发搜索操作。
在Vue 3里,watch用起来挺简单的。你得先引入它,然后告诉它要监听哪个数据,数据变化时要执行什么操作。比如:
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`count从${oldValue}变为了${newValue}`);
});
这里,count
是一个响应式数据,watch
就在盯着它。只要count
的值变化,就会执行后面的回调函数,newValue
和oldValue
分别是变化后和变化前的值。
响应式 API 的使用细节与注意点
1. reactive
和 ref
的组合使用
你可以将 reactive
和 ref
一起使用,通常 reactive
用来处理对象和数组,而 ref
用来处理原始数据类型。但它们可以相互结合。
import { reactive, ref } from 'vue';
export default {
setup() {
const count = ref(0);
const person = reactive({ name: 'Simin', age: 25 });
function increment() {
count.value++;
}
return { count, person, increment };
}
};
这里我们使用 reactive
来处理 person
对象,而使用 ref
来处理 count
数字。ref
和 reactive
可以互相协作,以创建更复杂的响应式状态。
响应式数据的嵌套与解构
在 Vue 3 中,响应式对象中的嵌套属性仍然是响应式的,这意味着当嵌套属性发生变化时,相关组件也会自动更新。
但是,如果你在 setup
中解构一个响应式对象或数组,解构出来的变量将不再是响应式的。
const state = reactive({ count: 0 });
const { count } = state; // 解构后 count 不再是响应式的
state.count++; // state.count 会触发更新,但 count 不会更新
要避免这个问题,建议使用 ref
或 reactive
的值时,尽量避免解构。如果需要解构,可以直接操作原对象或数组。
computed
的缓存与性能
computed
计算属性是基于依赖的,只会在相关依赖发生变化时重新计算。它们会缓存计算结果,直到依赖项发生变化。避免每次重新计算,提升了性能。
import { computed } from 'vue';
const state = reactive({ count: 0 });
const doubled = computed(() => state.count * 2);
在这里,doubled
会缓存 state.count
* 2 的计算结果,只有 state.count
改变时才会重新计算。