一、引言
Vue 3作为前端框架的新贵,以其轻量、高效、易用等特点受到了广大开发者的喜爱。在Vue 3中,computed和watch是两个非常重要的响应式API,它们在处理数据变化和执行异步操作方面发挥着重要作用。本文将通过案例,由浅入深地介绍computed和watch的使用方法,帮助大家更好地掌握这两个API。
二、computed的用法
1.计算属性简介
计算属性(computed)用于声明依赖响应式数据的计算值。简单点来说就是,当依赖的数据发生变化时,计算属性会自动重新计算。
案例1:计算商品总价
购物车场景,我们需要计算商品的总价,这里使用computed计算总价:
javascript
<template>
<div>
<p>商品单价:100元</p>
<p>购买数量:{{ count }}</p>
<p>商品总价:{{ totalPrice }}</p>
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const count = ref(1);
const totalPrice = computed(() => {
return count.value * 100;
});
return {
count,
totalPrice
};
}
};
</script>
-
const totalPrice = computed(() => { ... });
这里定义了一个名为totalPrice
的计算属性。**计算属性接收一个函数,该函数返回一个值。**这个值将根据依赖的响应式数据的变化自动更新。 -
当
count
的值改变时,computed
属性会自动重新计算,如果依赖的数据没有发生变化,则不会重新计算。 -
computed
属性总是同步更新的。当依赖的响应式数据变化时,计算属性会立即更新其值。
简而言之,在模板中使用 {``{ totalPrice }}
时,Vue 会自动读取 totalPrice
计算属性的当前值并将其渲染到页面上。当用户修改购买数量(count
)时,totalPrice
将自动更新,页面上的显示也会相应地改变。
案例2:计算a与b的和
javascript
<template>
<div>
<p>数值 A: <input v-model.number="a" /></p>
<p>数值 B: <input v-model.number="b" /></p>
<p>总和:{{ sum }}</p>
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
// 响应式引用:数值 A
const a = ref(0);
// 响应式引用:数值 B
const b = ref(0);
// 计算属性:数值 A 和 B 的和
const sum = computed(() => a.value + b.value);
// 暴露响应式引用和计算属性供模板使用
return {
a,
b,
sum
};
}
};
</script>
- 在模板中,我们展示了两个输入框,用户可以在其中输入数值,而计算属性
sum
会实时更新显示这两个数值的和。
注意
1.默认情况下,计算属性是只读的。如果尝试修改一个计算属性,Vue 会给出警告。如果需要设置计算属性的值,可以提供一个包含 set
方法的对象,但通常推荐保持计算属性只读。
2.计算属性是同步更新的。如果计算属性依赖于异步数据,应当在数据到达后再进行计算属性的依赖更新。
2.computed的setter方法
computed默认只有getter方法,但我们可以为其添加setter方法,以便在修改计算属性时执行一些操作。
javascript
const totalPrice = computed({
get() {
// 获取总价
const priceWithoutDiscount = unitPrice.value * count.value;
return priceWithoutDiscount * (1 - discount.value / 100);
},
set(newValue) {
// 设置总价,例如根据新的总价来调整折扣
// 注意:这个示例只是展示如何使用 set,实际上一般不会这样做
const priceWithoutDiscount = unitPrice.value * count.value;
discount.value = ((priceWithoutDiscount - newValue) / priceWithoutDiscount) * 100;
}
});
三、watch的基本用法
1.侦听器简介
侦听器(watch)用于观察和响应 Vue 实例上的数据变动。当数据变化时,会触发对应的回调函数。
案例1:监听输入框内容变化
以下是一个监听输入框内容变化的示例:
javascript
<template>
<div>
<input v-model="inputValue" />
<p>输入内容:{{ inputValue }}</p>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
const inputValue = ref('');
watch(inputValue, (newValue, oldValue) => {
console.log(`输入内容从${oldValue}变为${newValue}`);
});
return {
inputValue
};
}
};
</script>
2.watch的深度监听与立即执行
(1)深度监听
默认情况下,Vue 的 watch
不会侦听对象内部属性的变化。换句话说,如果只监听一个对象,而不是它的属性,那么只有当这个对象本身被替换时(即引用改变),watch
回调才会被触发。而我们希望能够侦听对象内部属性的变化,因此就出现了"深度监听"。
深度监听:当我们需要监听对象内部属性的变化时,可以设置deep选项为true。
案例1:
在这个例子中,我们将监听一个对象的内部属性变化。如果对象的属性发生变化,将会执行回调函数。
javascript
<template>
<div>
<p>姓名:{{ userInfo.name }}</p>
<p>年龄:{{ userInfo.age }}</p>
<button @click="updateName">修改姓名</button>
<button @click="updateAge">修改年龄</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
const userInfo = ref({
name: '张三',
age: 30
});
// 深度监听 userInfo 对象
watch(userInfo, (newValue, oldValue) => {
console.log('userInfo 对象发生变化:', newValue);
}, {
deep: true // 设置 deep 选项为 true,以深度监听对象内部属性的变化
});
// 修改姓名的方法
function updateName() {
userInfo.value.name = '李四';
}
// 修改年龄的方法
function updateAge() {
userInfo.value.age = 31;
}
return {
userInfo,
updateName,
updateAge
};
}
};
</script>
(2)立即执行
那什么时候用立即执行?
-
当需要在组件初始化时执行某些依赖于响应式数据的操作时,使用
immediate: true
可以确保这些操作在组件的mounted
钩子之前执行。 -
如果想要回调函数不仅应该在数据变化时执行,而且应该在一开始就根据当前值执行一次,那么
immediate: true
会很有用。
立即执行:默认情况下,watch会在被侦听的数据变化时执行回调函数。如果我们希望在组件初始化时立即执行回调函数,可以设置immediate选项为true。
案例1:立即执行
javascript
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="increment">增加</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
const count = ref(0);
// 监听 count 变化,并设置 immediate 选项为 true
watch(count, (newValue, oldValue) => {
console.log(`计数从 ${oldValue} 变为${newValue}`);
}, {
immediate: true // 设置 immediate 选项为 true,以在组件初始化时立即执行回调
});
// 增加 count 的方法
function increment() {
count.value++;
}
return {
count,
increment
};
}
};
</script>
五、使用场景辨析
|---------------------------------------------------------------------|------------------------------------------------------|
| 使用 computed
的场景 | 使用 watch
的场景 |
| 缓存计算结果:需要根据现有响应式数据派生出新数据时。 | 异步操作:需要在数据变化时执行异步操作或昂贵操作(如 API 调用)时。 |
| 同步操作:需要的数据依赖于其他响应式数据,并且这些依赖关系是同步的。 | 数据变化时的副作用:需要在数据变化时执行一些副作用时,比如更新另一个数据源或调用外部的回调函数。 |
| 模板内的复杂表达式 :模板中有复杂的表达式,为了保持模板的简洁性和可读性,可以将这些表达式移到 computed
属性中。 | 深度监听:需要监听对象内部属性的变化,或者数组的变化时。 |
| 复用逻辑 :如果计算逻辑需要在多个地方使用,使用 computed
可以避免代码重复。 | 立即执行:需要在侦听器创建时立即执行回调。 |
六、总结
本文通过案例由浅入深地介绍了Vue 3中computed和watch的使用方法。掌握这两个API的高级用法,有助于我们更好地处理响应式数据,提高开发效率。在实际项目中,应根据场景灵活运用computed和watch,充分发挥它们的优势。