一、computed
1. vue2和vue3中计算属性用法对比
Vue2中的计算属性
Vue2中的计算属性是通过在Vue实例的computed选项中定义函数来创建的。计算属性会根据依赖的响应式属性进行缓存,只有当依赖的属性发生变化时,计算属性才会重新求值。
举个例子,假设有一个Vue实例:
new Vue({
data: {
firstName: 'John',
lastName: 'Doe'
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
}
}
})
在这个例子中,fullName就是一个计算属性,它依赖于firstName和lastName两个响应式属性。当firstName或者lastName的值发生变化时,fullName会重新计算。
Vue3中的计算属性
而在Vue3中,计算属性被重命名为"由计算值推导而来的属性"或者简称"计算值"。Vue3提供了一个新的API,使用computed
函数创建计算值。
举个例子,假设有一个Vue3的Composition API实例:
import { reactive, computed } from 'vue';
const state = reactive({
firstName: 'John',
lastName: 'Doe'
});
const fullName = computed(() => {
return state.firstName + ' ' + state.lastName;
});
在这个例子中,fullName
就是一个计算值,它依赖于state
对象中的firstName
和lastName
两个属性。当firstName
或者lastName
的值发生变化时,fullName
会重新计算。
在用法上,Vue3中的计算值需要使用computed
函数创建,而Vue2中的计算属性直接在computed
选项中定义函数即可。
另外,Vue3中的计算值可以在组合式API中使用,这给开发者提供了更大的灵活性和便利性,可以更好地组织和复用代码。而Vue2中的计算属性只能在Vue实例中直接使用。
总结起来,Vue2中的计算属性和Vue3中的计算值在使用方式上有一些区别,Vue3中的计算值具有更大的灵活性,可以在组合式API中使用,而Vue2中的计算属性只能在Vue实例中使用。
2. vue3中的computed完整用法
在上面的例子中只是简单使用了computed,它是只读的,我们并不能修改。
computed的完整用法如下:
- 定义computed属性:可以使用
computed
函数定义计算属性。在函数中,可以通过get
和set
来分别定义计算属性的取值和赋值函数。
import { computed } from 'vue';
const myData = computed({
get() {
// 计算并返回计算属性的值
},
set(value) {
// 处理计算属性的赋值操作
}
});
- 使用计算属性:计算属性的值可以像普通的数据属性一样在模板中使用。
<template>
<div>
<p>{{ myData }}</p>
</div>
</template>
举个例子:
<template>
姓:<input type="text" v-model="firstName">
<br>
名:<input type="text" v-model="lastName">
<br>
<span>全名:{{fullName}}</span>
<br>
全名:<input type="text" v-model="fullName">
</template>
<script>
import {reactive,computed, toRefs} from 'vue'
export default {
name: 'Demo',
setup(){
//数据
let person = reactive({
firstName:'张',
lastName:'三'
})
//计算属性——简写(没有考虑计算属性被修改的情况)
/* person.fullName = computed(()=>{
return person.firstName + '-' + person.lastName
}) */
//计算属性——完整写法(考虑读和写)
person.fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
//返回一个对象(常用)
return {
...toRefs(person)
}
}
}
</script>
二、watch
1. vue2中watch的使用
在Vue2中,watch是一个用于侦听数据变化并执行相应逻辑的侦听器。它可以监听一个特定的数据源,并在该数据源发生变化时执行回调函数。
下面是多个角度的例子来说明watch的使用:
- 监听简单变量的变化:
data() {
return {
count: 0
}
},
watch: {
count(newVal, oldVal) {
console.log(`count的值从${oldVal}变为${newVal}`);
}
}
在这个例子中,我们监听了count变量的变化,并在变化时打印出旧值和新值。
- 监听对象属性的变化:
data() {
return {
user: {
name: 'John',
age: 25
}
}
},
watch: {
'user.name'(newVal, oldVal) {
console.log(`user.name的值从${oldVal}变为${newVal}`);
}
}
在这个例子中,我们监听了user对象中的name属性的变化,并在变化时打印出旧值和新值。
- 监听数组的变化:
data() {
return {
todos: ['a', 'b', 'c']
}
},
watch: {
todos: {
handler(newVal, oldVal) {
console.log(`todos数组发生变化`);
},
deep: true
}
}
在这个例子中,我们监听了todos数组的变化,并在变化时打印出提示信息。通过设置deep: true
,也可以监听数组中元素的变化。
- 使用immediate属性:
data() {
return {
value: 0
}
},
watch: {
value: {
handler(newVal, oldVal) {
console.log(`value的值从${oldVal}变为${newVal}`);
},
immediate: true
}
}
在这个例子中,我们设置了immediate属性为true,这将使得watch立即执行一次回调函数。
watch是Vue2中用于侦听数据变化的重要工具,可以在数据发生变化时执行相应的操作。无论是简单变量、对象属性还是数组,都可以使用watch来监听变化,从而实现一些复杂的逻辑。
2. vue3中watch的使用
在Vue 3中,watch侦听器函数用于监视响应式数据的变化。它可以用来执行一些逻辑或触发其他更新。
使用方法如下:
watch(要观察的数据, 回调函数, 配置选项)
- 监视ref所定义的一个响应式数据:
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`count的值从${oldValue}变为${newValue}`);
});
- 监视ref所定义的多个响应式数据:
import { ref, watch } from 'vue';
const count1 = ref(0);
const count2 = ref(0);
watch([count1, count2], (newVal, oldVal) => {
// 这里的newVal和oldVal是一个数组[count1, count2]
console.log(`count的值从${oldVal}变为${newVal}`);
});
- 监视reactive所定义的一个响应式数据的全部属性:
import { reactive, watch } from 'vue';
const person = reactive({
name: '张三',
age: 20,
});
watch(person, (newValue, oldValue) => {
console.log(`person的值从${JSON.stringify(oldValue)}变为${JSON.stringify(newValue)}`);
});
- 监视reactive所定义的一个响应式数据中的某个属性:
import { reactive, watch } from 'vue';
const person = reactive({
name: '张三',
age: 20,
});
watch(() => person.name, (newValue, oldValue) => {
console.log(`person.name的值从${oldValue}变为${newValue}`);
});
- 监视reactive所定义的一个响应式数据中的某些属性:
import { reactive, watch } from 'vue';
const person = reactive({
name: '张三',
age: 20,
gender: '男',
});
watch([() => person.age, () => person.gender], (newValue, oldValue) => {
// 这里的newValue和oldValue是一个数组[person.age, person.gender]
console.log('person中的age或者gender发生了变化', newValue, oldValue)
});
这里需要注意的是watch在监听reactive报装的对象时有三个坑
- 无法正确的获取oldValue
就拿上面的第三个情况来说,
import { reactive, watch } from 'vue';
const person = reactive({
name: '张三',
age: 20,
});
watch(person, (newValue, oldValue) => {
console.log('person变化了',newValue,oldValue)
});
从打印可以看出,每次打印的newValue和oldValue是一样的。无法正确获取上次的oldValue
- 强制开启了深度监视(deep配置无效)
let person = reactive({
name:'张三',
age:18,
job:{
chengxuyuan:{
salary:20
}
}
})
watch(person, (newValue, oldValue) => {
console.log('person变化了',newValue,oldValue)
});
当我们修改person中的job对象下的salary时,此处我们不用配置deep,它默认就可以深度监听,并且配置{deep: false}也无法关闭它的监听。
- 监视的是reactive定义的对象中的某个属性依然是个对象时,又需要配置deep,并且这时的oldValue依然无法正确获取
接着上面的第二个坑讲,此时如果我们这样监听job
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true})
这个时候又需要{deep: true}配置了,如果不配置deep,它又监听不到,并且此时的oldValue值依然是无法正确获取的,和newValue一样。
3. watchEffect
watchEffect函数是Vue 3中的一个新增特性,用于在组件渲染过程中执行副作用代码。它接收一个无参数回调函数作为参数,并自动追踪回调中所使用的响应式数据。
使用watchEffect函数,可以实现类似于Vue 2中的watch函数的效果,但比watch函数更灵活和强大。下面我们从多个角度举例分析说明watchEffect函数的用法。
watchEffect()会在组件渲染之前执行一次,返回值是一个用来停止该副作用的函数。
- 基本用法:
import { watchEffect, reactive, ref } from 'vue'
const data = reactive({ count: 0 })
watchEffect(() => {
console.log(data.count)
})
在上面的例子中,我们使用watchEffect函数来监视响应式数据data中的count属性,当count发生变化时,副作用代码即回调函数中的console.log语句会被执行。
- 处理副作用:
import { watchEffect, ref } from 'vue'
const count = ref(0)
watchEffect(() => {
document.title = `Count: ${count.value}`
})
在上面的例子中,我们使用watchEffect函数来改变页面的标题,当count的值发生改变时,页面的标题会动态更新。
- 控制副作用:
import { watchEffect, ref } from 'vue'
const sum= ref(0)
const stop = watchEffect(() => {
console.log('sum变了', sum.value)
// 当不再需要此侦听器时:
if (sum.value > 10) {
stop()
}
})
在上面的例子中,我们使用watchEffect函数来执行一个具有控制能力的副作用代码。当sum的值大于10之后我们就可以定制watchEffect监听
- 异步处理:
import { watchEffect, ref, nextTick } from 'vue'
const count = ref(0)
watchEffect(async () => {
await nextTick()
console.log('异步副作用被执行')
})
在上面的例子中,我们使用watchEffect函数来处理异步的副作用代码。在回调函数中使用async/await语法,通过nextTick函数来等待组件更新完成后执行副作用代码。
总结:
watchEffect函数是Vue 3中用于执行副作用代码的强大工具,它可以自动追踪响应式数据的变化,并在数据发生改变时执行回调函数。通过它,我们可以非常灵活地处理副作用逻辑,包括修改页面元素、清除副作用、处理异步等。在日常开发中,合理利用watchEffect函数可以让我们更加高效地编写响应式代码。
4.watchEffect和computed的区别
watchEffect函数 | computed函数 | |
---|---|---|
基本作用 | 监听函数内部的响应式数据变化,执行相应的副作用操作 | 根据响应式数据的变化自动计算得到新的结果,并缓存起来供后续使用 |
使用方式 | watchEffect(() => { | const double = computed(() => value.value * 2); |
// 监听响应式数据的变化 | // 响应式数据变化,自动计算新结果并缓存 | |
侦听的数据 | 响应式数据 | 响应式数据 |
依赖追踪 | 自动追踪响应式数据的变化 | 手动指定所依赖的响应式数据 |
执行时机 | 在组件渲染期间立即执行 | 仅在所依赖的响应式数据发生变化时执行 |
使用场景 | 需要在响应式数据发生变化时执行副作用操作 | 需要根据响应式数据的变化自动计算得到新的结果,并缓存起来供后续使用 |
需要使用已计算得到的结果进行其他操作,而不是每次都重新计算 |
在上述表格中,我们可以看到watchEffect函数和computed函数的不同之处。
watchEffect函数用于监听响应式数据的变化,在数据发生变化时执行副作用操作。它可以自动追踪响应式数据的变化,并在组件渲染期间立即执行副作用操作。watchEffect函数不需要手动指定依赖的响应式数据,它会自动追踪响应式数据的变化并执行副作用操作。适合于需要在响应式数据发生变化时执行副作用操作的场景。
computed函数用于根据响应式数据的变化自动计算得到新的结果,并缓存起来供后续使用。它需要手动指定所依赖的响应式数据,只有所依赖的响应式数据发生变化时,computed函数才会执行并返回新的结果。computed函数适合于需要使用已计算得到的结果进行其他操作,而不是每次都重新计算的场景。
举例来说明
假设有一个计数器和一个值,需要在计数器发生变化时输出计数器的值,而在值发生变化时输出值的两倍。则可以使用watchEffect函数监听计数器的变化,并输出计数器的值;同时使用computed函数监听值的变化,并计算得到值的两倍。当计数器发生变化时,watchEffect会立即执行输出计数器的值;当值发生变化时,computed函数会自动计算得到新的两倍值,并缓存起来供后续使用。
import { reactive, watchEffect, computed } from 'vue';
const state = reactive({
counter: 0,
value: 5,
});
watchEffect(() => {
console.log('Counter:', state.counter);
});
const doubleValue = computed(() => {
return state.value * 2;
});
watchEffect(() => {
console.log('Double Value:', doubleValue.value);
});
state.counter++; // Output: Counter: 1
state.value = 10; // Output: Double Value: 20
当计数器发生变化时,watchEffect会立即执行,并输出计数器的值。当值发生变化时,computed函数会自动计算得到新的两倍值(20),并输出结果。
需要注意的是,watchEffect函数不会缓存计算结果,每次发生变化都会重新执行回调函数。而computed函数会自动缓存计算结果,只有当依赖的响应式数据发生变化时才会重新计算值。