Vue3的计算属性与监视

204 阅读3分钟

computed函数

vue3中的计算属性与vue2的配置功能一致,但在setup函数中使用必须先引入,写法如下:

import { reactive, computed } from 'vue'

setup(){
    const person = reactive({
        firstName: '张',
        lastName: '三',
    })
    // 计算属性——只读当修改fullName时,firstName和lastName不变
    person.fullName = computed(() => {
        return person.firstName + '-' + person.lastName
    })
    
    // 计算属性——可以读写
    person.fullName = computed({
        // 读取fullName
        get(){
            return person.firstName + '-' + person.lastName
        },
        // 修改fullName
        set(newValue){
            // 修改后的fullName分割得到firstName和lastName
            const nameArr = newValue.split('-')
            person.firstName = nameArr[0]
            person.lastName = nameArr[1]
        }
    })
    
    return {
        person
    }
}

watch函数

vue3的watch函数参数分别为被监视属性、回调函数和其他配置,与vue2的配置功能一致,根据refreactive定义响应式数据分为以下几种情况:

  1. watch监视ref定义的响应式数据
<button @click="sum++"></button>
...
let sum = ref(0)
watch(sum, (newValue, oldValue)=>{
    console.log('sum变化了',newValue,oldValue)
}, {immediate: true})

// 'sum变化了,1,0'

特殊情况:watch监听ref定义的响应式数据为对象

<button @click="person.age++"></button>

let person = ref({
    name: 'ls',
    age: 20
})

// ref定义的person是一个RefImpl对象,真正的数据存放在value属性中,无法直接监视person
watch(person, (newValue, oldValue)=> {
    console.log('person的age变化了')
})

// 解决方法1:监视真正的数据(等同于情况3)
watch(person.value, (newValue, oldValue)=> {
    console.log('person的age变化了')
})

// 解决方法2:value属性的值是一个proxy对象,开启deep(等同于情况4的特殊情况)
watch(person, (newValue, oldValue)=> {
    console.log('person的age变化了')
}, {deep:true})
  1. watch监视多个ref定义的响应式数据
<button @click="sum++"></button>
<button @click="msg+='!'"></button>

let sum = ref(0)
let msg = '你好啊'
// 被监视的多个属性放在一个数组中
watch([sum, msg], (newValue, oldValue)=>{
    console.log('sum或msg变化了',newValue,oldValue)   
}, {immediate: true})

// 'sum或msg变化了,[1,'你好啊'],[0,'你好啊']'
// 'sum或msg变化了,[1,'你好啊!'],[1,'你好啊']'
  1. watch监视reactive定义的响应式数据
<button @click="person.name+='~'"></button>
<button @click="person.age++"></button>

let person = reactive({
    name: 'zs',
    age: 18
})

watch(person, (newValue, oldValue)=>{
    console.log('person变化了',newValue,oldValue)
}, {immediate: true, deep: false}) // 此处deep配置不生效

// 'person变化了', {name: 'zs~',age: 18},{name: 'zs~',age: 18}
// 'person变化了', {name: 'zs~',age: 19},{name: 'zs~',age: 19}

当监视reactive定义的响应式数据时,oldValue无法获取,且深度监视被强制开启。

  1. watch监视reactive定义的响应式数据的某个属性
<button @click="person.name+='~'"></button>

let person = reactive({
    name: 'zs',
    age: 18,
    job: {
        j1: {
            salary: 20
        }
    }
})

// 此时被监视对象需要放入函数中
watch(()=>person.name, (newValue, oldValue)=>{
    console.log('person的name变化了',newValue,oldValue)
})

// 'person的name变化了,zs~, zs'

特殊情况:当reactive定义的响应式数据的某个属性的值为对象时,需要开启deep配置

<button @click="person.job.j1.salary++"></button>

let person = reactive({
    name: 'zs',
    age: 18,
    job: {
        j1: {
            salary: 20
        }
    }
})
watch(()=>person.job, (newValue, oldValue)=>{
    console.log('person的job变化了',newValue,oldValue)
}, {deep: true})
// person的job变化了 {j1:{salary:21}} {j1:{salary:21}}
  1. watch监视reactive定义的响应式数据的多个属性
<button @click="person.name+='~'"></button>
<button @click="person.age++'~'"></button>

let person = reactive({
    name: 'zs',
    age: 18
})

watch([()=>person.name, ()=>person.age], (newValue, oldValue)=>{
    console.log('person的name或age变化了',newValue,oldValue)
})

// person的name或age变化了 ['zs~', 18] ['zs', 18]
// person的name或age变化了 ['zs~', 19] ['zs~', 18]

watchEffect函数

watchEffect函数监视所指定回调函数中用到的属性,若回调中的数据发生变化,则会重新执行回调。

import { watchEffect } from 'vue'
// ...
setup(){
    let sum = ref(0)

    // 回调中用到sum,只要sum变化就会打印'watchEffect回调执行了'
    watchEffect(()=>{
        const x1 = sum.value
        console.log('watchEffect回调执行了')
    })
    
    return {
        sum
    }
}

与computed和watch比较

  1. watch函数既指明监视的属性,也指明监视的回调;watchEffect函数不指明监视的属性
  2. computed注重计算出来的值(回调函数的返回值),所以必须写return;watchEffect注重执行过程(回调函数的函数体),所以不用写return