1、computed() 计算属性
在模板中绑定表达式只能用于简单的运算。如果运算比较复杂,可以使用 Vue.js 提供的计算属性,通过计算属性可以处理比较复杂的逻辑。
1.1 计算属性的应用
通过计算属性可以实现各种复杂的逻辑,包括运算、函数调用等,只要最后返回一个计算结果就可以。当计算属性依赖的数据发生变化时,计算属性的值会自动更新,所有依赖该计算属性的数据绑定也会同步进行更新。
【实例】使用 computed 计算属性,实现每个单词首字母大写。
<template>
<p>原字符串:{{ data }}</p>
<p>新字符串:{{ newData }}</p>
</template>
<script setup>
//导入函数
import { ref, computed } from 'vue';
//创建一个响应式代理对象
const data = ref('my heart will go on');
//计算方法:实现首字母大写
const newData = computed(() => {
let arr = data.value.split(' '); //注意:使用响应式对象的.value属性,获取内部值
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1).toLowerCase();
}
return arr.join(' ');
});
</script>
执行结果:
2.2 计算属性的 getter 和 setter
每一个计算属性都包含一个 getter 和一个 setter。getter 只要用来读取值,而 setter 主要用来设置值。getter 主要用来读取值,而 setter 主要用来设置值。当手动更新计算属性的值时,就会触发 setter,执行一些自定义的操作。
【实例】使用 计算属性的 getter 和 setter,重新设置人物姓名。
<template>
<p>人物名称:{{ person.fullname }}</p>
</template>
<script setup>
//导入函数
import { reactive, computed } from 'vue';
//创建一个响应式代理对象
const person = reactive({
firstName: 'Jim',
lastName: 'Carrey'
});
// 计算属性 - 简写
// person.fullName = computed(() => {
// return `${person.firstName} ${person.lastName}`
// })
//计算属性的 getter 和 setter
person.fullname = computed({
get() {
return `${person.firstName} ${person.lastName}`
},
set(value) {
const arr = value.split(' ');
person.firstName = arr[0]
person.lastName = arr[1]
}
});
//重新设置人物名称
person.fullname = 'Will Smith';
</script>
执行结果:
1.3 methods 与 computed 的区别
问:Vue 中的 methods 方法与 computed 计算属性有什么区别?
答:主要区别是 methods 方法会实时计算,而 computed 计算属性是使用缓存数据。
将相同的操作定义为一个方法,或者定义为一个计算属性,两种方式的结果完全相同。那么为什么还需要计算属性呢?因为计算属性是基于它们的依赖进行缓存的。当页面重新渲染时,如果依赖的数据未发生改变,使用计算属性获取的值就是一直是缓存值。只有依赖的数据发生改变时才会重新获取值。如果使用的是方法,在页面重新渲染时,方法中的函数总会被重新调用。
详情请浏览本博客的文章:《Vue中的methods方法与computed计算属性的区别》
2、watch() 监听器
watch() 方法相当于 Vue 根实例选项对象中的 watch 选项。该方法用于监听特定的数据,并在回调函数中应用。当被监听的数据发生变化时,才会调用回调函数。
2.1 监听 ref 响应式对象
watch() 方法可以接收两个参数。如果使用该方法监听的是一个 ref 对象,那么第一个参数需要监听的 ref 对象,第二个参数是当监听的数据发生变化时触发的回调函数。
【实例】使用 watch() 方法监听一个 ref 响应式对象,实现“米”和“厘米”单元的换算结果。
<template>
请输入米数:<input type="text" size="6" v-model="data" />
<p>换算结果:{{ result }}</p>
</template>
<script setup>
//导入函数
import { ref, watch } from 'vue';
//创建一个 ref 响应式代理对象
const data = ref(0);
//换算结果变量
const result = ref('');
//watch监听器
watch(data, (newValue, oldValue) => {
console.log("新值", newValue);
console.log("旧值", oldValue);
result.value = `${data.value} 米 = ${data.value * 100} 厘米`;
});
</script>
执行结果:
2.2 监听 reactive 响应式对象
如果 watch() 方法监听的是一个 reactive 对象中的某个属性,那么第一个参数需要使用返回该属性的函数的方式。
watch() 方法的两个额外参数:
1、immediate:是否立即执行。
2、deep:是否深度监听。
注意:
如果要监听的属性值是一个对象,要想监听对象内部值的变化,需要在监听属性的选项参数中设置 deep 选项的值为 true(开启深度监听)。
【实例2】使用 watch() 方法监听一个 reactive 响应式对象中的某个属性,输出属性的原值和新值。
<template>
<p>商品名称:{{ product.name }}</p>
<p>{{ product.remark }}</p>
</template>
<script setup>
//导入函数
import { reactive, watch } from 'vue';
//创建一个 reactive 响应式代理对象
const product = reactive({
name: '华为手机',
price: 6999,
remark: ''
});
//watch监听器
watch(() => product.price, (newValue, oldValue) => {
product.remark = `原价格:${oldValue}元,新价格:${newValue}元`;
},
//两个额外参数(非必填)
{
immediate: false, //关闭:立即监听;默认关闭
deep: true //开启:深度监听;如果监听对象是 reactive() 响应式对象,则默认自动开启
});
//修改属性值
product.price = 3999;
</script>
执行结果:
2.3 监听多个属性
监听属性通常用来实现数据之间的换算,如长度单位之间的换算、速度单位之间的换算、汇率之间的换算等。
【实例】使用 watch() 方法监听多个属性,实现速度单位之间的换算。
<template>
<p>
<label for="meter">米/秒:</label>
<input id="meter" type="number" v-model="meter">
</p>
<p>
<label for="kilometer">千米/小时:</label>
<input id="kilometer" type="number" v-model="kilometer">
</p>
{{ meter }}米/秒={{ kilometer }}千米/小时
</template>
<script setup>
//导入函数
import { ref, watch } from 'vue';
//创建两个 ref 响应式代理对象
const meter = ref(0);
const kilometer = ref(0);
//watch监听器:监听多个属性
watch([meter, kilometer],
([newMeter, newKilometer], [oldMeter, oldKilometer]) => {
if (newMeter != oldMeter) {
kilometer.value = newMeter * 3600 / 1000;
}
if (newKilometer != oldKilometer) {
meter.value = newKilometer * 1000 / 3600;
}
}
);
</script>
执行结果:
3、watchEffect() 高级监听器
3.1 watchEffect() 的使用
watchEffect() 方法用来监听数据的变化,类似于 Vue 2.x 中的 watch 选项。该方法接收一个函数作为参数,它会立即执行一次,同时会跟踪函数里面用到的所有响应式状态,当状态发生变化时会重新运行该函数。
【实例】使用 watchEffect() 方法监听数据,实现“米”和“厘米”单元的换算结果。
<template>
请输入米数:<input type="text" size="6" v-model="data" />
<p>换算结果:{{ result }}</p>
</template>
<script setup>
//导入函数
import { ref, watchEffect } from 'vue';
//创建一个 ref 响应式代理对象
const data = ref(0);
//换算结果变量
const result = ref('');
//watch监听器
watchEffect(() => {
result.value = `${data.value} 米 = ${data.value * 100} 厘米`;
});
</script>
执行结果:
3.2 watch 和 watchEffect 的区别
watch 和 watchEffect 是 Vue 3.0 中新增的两个响应式 API,用于监听数据的变化。watch 适用于需要获取新值和旧值,或者需要懒执行的场景,而 watchEffect 适用于需要监听多个数据源,并且需要立即执行的场景。它们之间的区别如下:
- watch 是监听单个数据源,可以设置 immediate 和 deep 选项,可以获取新值和旧值;watchEffect 则是监听一组数据源,不能设置 immediate 和 deep 选项,不能获取新值和旧值。
- watch 是懒执行的,只有在数据变化时才会执行回调函数,而 watchEffect 则是立即执行的,不管数据是否变化。
- watch 可以监听计算属性,而 watchEffect 不能监听计算属性。