[TOC]

参考文档:https://juejin.cn/post/7005140118960865317/#heading-26

1. computed

import { computed } from 'vue'

const 计算属性名 = computed(() => {
  return 响应式数据相关计算
})

1.1 简写

<template>
    <div>
        <h2>姓:{{person.firstName}}</h2>
        <h2>名:{{person.lastName}}</h2>
        <h2>全名:{{fullName}}</h2>
    </div>
</template>

<script>
import { computed, reactive} from'vue'
export default { 
  setup() {
    const person = reactive({
        firstName:'张',
        lastName:'三'
    })
    const fullName = computed(() => {
        return person.firstName +'-'+ person.lastName
    })

    return { person ,fullName}
  },
}
</script>

1.2 高级用法

 const fullName = computed({
      get() {
        return person.firstName + '-' + person.lastName
      },
      set(value) {
        const nameArr = value.split('-')
        person.firstName = nameArr[0]
        person.lastName = nameArr[1]
      },
    })

1.3 computed传参

<template>
  <div>
    <h3>count:{{getCountByParams(10,20)}}</h3>
  </div>
</template>

<script>
import { computed, reactive } from 'vue'
export default {
  setup() {
    const getCountByParams = computed(() => (a,b) => {
        return a*b
    })

    return { getCountByParams }
  },
}
</script>

image.png

2. watch

:::success watch(person, (newValue, oldValue) => {
console.log(newValue, oldValue)
},{deep: true}, {immediate: true}) :::

2.1 监听ref定义的响应式数据

<template>
  <div>
    <h3>count:{{count}}</h3>
    <button @click="add">add</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue'
export default {
  setup() {
    const count = ref(0)
    function add() {
      count.value++
    }
    watch(count, (newValue, oldValue) => {
        console.log(newValue, oldValue)

    })
    return { count, add, }
  },
}
</script>

此处监听是, 只能写count, 不能写count.value。因为, 如果写count.value, 那么次数相当于监听的是0。 此时真正监听的RefImpl这个对象。
image.png

2.2 监听多个ref定义的响应式数据

<template>
  <div>
    <h3>count:{{count}}</h3>
     <h3>sum:{{sum}}</h3>
    <button @click="add">add</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue'
export default {
  setup() {
    let count = ref(10)
    let sum = ref(20)
    function add() {
      count.value++
      sum.value *= 10
    }
    watch([count, sum], (newValue, oldValue) => {
        console.log(newValue, oldValue) //[12, 2000] (2) [11, 200]
    /*
      newValue时一个数组:包含count和sum的变化后的值
      oldValue时一个数组:包含count和sum的变化前的值
    */
    } ,{immediate:true})
    return { count,sum, add, }
  },
}

2.3 监听reactive定义的响应式数据

如果监听用reactive定义的响应式数据, 此处无法正确的监听oldValue。

<template>
  <div>
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <button @click="person.name +='@'">修改姓名</button>
    <button @click="person.age ++">修改年龄</button>
  </div>
</template>

<script>
import { reactive, watch } from 'vue'
export default {
  setup() {
    const person = reactive({
      name: '张三',
      age: 20,
    })
    watch(person, (newValue, oldValue) => {
        console.log(newValue, oldValue)
    })
    return {  person }
  },
}
</script>

image.png
如果直接把reactive换成ref,用watch监听, 则监听不到变化。

<script>
import { reactive, watch ,ref} from 'vue'
export default {
  setup() {
    const person = ref({
      name: '张三',
      age: 20,
    })
    watch(person, (newValue, oldValue) => {
        console.log(newValue, oldValue)
    })
    return {  person }
  },
}
</script>

如果打开深度监听,则可以监听到oldValue

import { reactive, watch ,ref} from 'vue'
export default {
  setup() {
    const person = ref({
      name: '张三',
      age: 20,
    })
    console.log(person)
    watch(person, (newValue, oldValue) => {
        console.log(newValue, oldValue)
    },{deep: true})
    return {  person }
  },
}
</script>

如果换成监听ref对应的value值, 则出现和reactive一样的问题, 还是监听不到oldValue。因为用ref定义的引用类型的响应式数据, 它的底层还是借助于reactive实现的。

import { reactive, watch ,ref} from 'vue'
export default {
  setup() {
    const person = ref({
      name: '张三',
      age: 20,
    })
    console.log(person)
    watch(person.value, (newValue, oldValue) => {
        console.log(newValue, oldValue)
    })
    return {  person }
  },
}
</script>

为啥这里可以写person.value。 因为此时的person.value对应的值是一个proxy
image.png

2.4 监视整个对象

  • watch监视的是reactive定义的响应式数据,则强制开启了深度监视
    watch(person,(newValue,oldValue)=>{
      console.log('person变化了',newValue,oldValue)
    },{immediate:true,deep:false}) //此处的deep配置不再奏效
    
    ```javascript
``` ![image.png](https://cdn.nlark.com/yuque/0/2022/png/27402074/1658802275015-a95c47e6-3b76-4479-ad10-81933b79eff0.png#clientId=uf629d92c-60d7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=328&id=ubb808aab&margin=%5Bobject%20Object%5D&name=image.png&originHeight=492&originWidth=1762&originalType=binary&ratio=1&rotation=0&showTitle=false&size=112687&status=done&style=none&taskId=u282f459c-b3c4-47e2-81e2-6127f4a3a4f&title=&width=1174.6666666666667)
监视**age**属性,可以正确拿到**oldValue**值 ```javascript
![image.png](https://cdn.nlark.com/yuque/0/2022/png/27402074/1658802464086-952072c1-f326-4a01-906a-1647650d079b.png#clientId=uf629d92c-60d7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=351&id=ub6109939&margin=%5Bobject%20Object%5D&name=image.png&originHeight=526&originWidth=1228&originalType=binary&ratio=1&rotation=0&showTitle=false&size=52283&status=done&style=none&taskId=u22b14a7e-d9af-43a7-ab30-3ad67170229&title=&width=818.6666666666666)<br />监听多个属性, 放在**[]**中, 可以拿到正确的**oldValue**
```javascript
<script>
import { reactive, watch ,ref} from 'vue'
export default {
  setup() {
    const person = reactive({
      name: '张三',
      age: 20,
      job:{
        salery:20
      }
    })
    watch([() => person.age, () => person.name], (newValue, oldValue) => {
        console.log(newValue, oldValue)
    })
    return {  person }
  },
}
</script>

image.png
如果person对象的属性值为一个对象, 则需要开启深度监视:

<script>
import { reactive, watch ,ref} from 'vue'
export default {
  setup() {
    const person = reactive({
      name: '张三',
      age: 20,
      job:{
        salery:20
      }
    })
    watch(() => person.job, (newValue, oldValue) => {
        console.log(newValue, oldValue)
    },{deep: true})
    return {  person }
  },
}
</script>
  • image.png

    3. watchEffect函数

  • watch的套路是:既要指明监视的属性,也要指明监视的回调。
  • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
  • watchEffect有点像computed:
    • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
    • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
    • 默认开启了immediate: true,首次就会执行一次。

watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。

<script>
import { reactive, watch ,ref, watchEffect} from 'vue'
export default {
  setup() {
    const person = reactive({
      name: '张三',
      age: 20,
    })
    console.log(person)
     watchEffect(() => {
      const m = person.name;
      const n = person.age;
      console.log('我执行了')
    })
    return {  person }

  },
}
</script>