Vue3:computed计算属性和watch监视以及watchEffect函数原理和用法(含vue2用法)

发布时间:2023年12月18日

1. computed

1. computed

<template>
  <input v-model="person.firstName" />
  <br />
  <input v-model="person.lastName" />

  <div>全名: {{ person.fullName }}</div>

  <input v-model="person.fullName" />
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  name: 'DemoComponent',
  // vue2计算属性的写法
  // computed: {
  //   fullName() {
  //     return `${this.person.firstName}-${this.person.lastName}`
  //   }
  // },
  setup() {
    const person = reactive({
      firstName: '张',
      lastName: '三'
    })

    // 计算属性 - 简写
    // person.fullName = computed(() => {
    //   return `${person.firstName}-${person.lastName}`
    // })

    // 计算属性 - 完整
    person.fullName = computed({
      get() {
        return `${person.firstName}-${person.lastName}`
      },
      set(value) {
        const arr = value.split('-');
        person.firstName = arr[0]
        person.lastName = arr[1]
      }
    })

    return {
      person,
    }
  }
}
</script>

2. watch监听ref和reactive响应式数据基本用法

watch函数两个小坑:
1. 监视reactive定义的响应式数据时,oldValue无法正确获取,且强制开启了深度监视(deep配置无效)
2. 监视reactive定义的响应式数据中的某个属性时(非对象时),deep配置有效

代码演示如下:
<template>
  <div>{{ sum }}</div>
  <button @click="sum++">sum按钮</button>
  <div>{{ msg }}</div>
  <button @click="msg += `!`">msg按钮</button>
  <hr />

  <div>{{ person.name }}</div>
  <button @click="person.name += '~'">按钮name</button>
  <div>{{ person.job.j1.salary }}</div>
  <button @click="person.job.j1.salary++">按钮salary</button>
</template>

<script>
import { reactive, ref, watch } from 'vue'

export default {
  name: 'DemoComponent',
  // // vue2监视属性的写法 - 简写
  // watch: {
  //   sum(newValue, oldValue) {
  //     console.log(newValue, oldValue);
  //   },
  //   msg(newValue, oldValue) {
  //     console.log(newValue, oldValue);
  //   }
  // },

  // // vue2监视属性的写法 - 完整
  // watch: {
  //   sum: {
  //     immediate: true, // 立即生效
  //     handler(newValue, oldValue) {
  //       console.log(newValue, oldValue);
  //     },
  //   },
  //   msg: {
  //     immediate: true,
  //     handler(newValue, oldValue) {
  //       console.log(newValue, oldValue);
  //     }
  //   }
  // },
  setup() {
    let sum = ref(0);
    let msg = ref('你好啊')

    let person = reactive({
      name: '张三',
      job: {
        j1: {
          salary: 20
        }
      }
    })

    // 情况一:监视ref所定义的一个响应式数据
    // watch(sum, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, {immediate: true})

    // 情况二:监视ref所定义的多个响应式数据
    // watch([sum, msg], (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, { immediate: true })

    // 情况三:监视reactive所定义的一个响应式数据
    /**
     * 注意1:此处无法正确获取oldValue
     * 注意2:强制开启了深度监视(配置deep无效)
     */
    // watch(person, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, {deep: false}) // 此处的deep无效

    // 情况四:监视reactive所定义的一个响应式数据中的某个属性
    // watch(() => person.name, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, { immediate: true })

    // 情况五:监视reactive所定义的一个响应式数据中的"某些"属性
    // watch([() => person.name], (newValue, oldValue)   => {
    //   // 多个用数组,[() => person.job, () => person.age]
    //   console.log(newValue, oldValue);
    // }, {immediate: true})

    // 特殊情况, 监听reactive内的某个对象属性,如果没开启深度监视deep,那么将无法监听到改变, 当然此处与情况三一样,此处无法正确获取oldValue
    watch(() => person.job, (newValue, oldValue) => {
      console.log(newValue, oldValue);
    }, {immediate: true, deep: true})

    return {
      sum,
      msg,
      person
    }
  }
}
</script>

3. watch监听ref时value的问题

具体案例代码如下:

<template>
  <div>{{ sum }}</div>
  <button @click="sum++">sum按钮</button>
  <div>{{ msg }}</div>
  <button @click="msg += `!`">msg按钮</button>
  <hr />

  <div>{{ person.name }}</div>
  <button @click="person.name += '~'">按钮name</button>
  <div>{{ person.job.j1.salary }}</div>
  <button @click="person.job.j1.salary++">按钮salary</button>
</template>

<script>
import { ref, watch } from 'vue'

export default {
  name: 'DemoComponent',
  setup() {
    let sum = ref(0);
    let msg = ref('你好啊')

    let person = ref({
      name: '张三',
      job: {
        j1: {
          salary: 20
        }
      }
    })

    // 监听基本数据类型不需要.value,因为监听的是Impl对象,value发生改变就能监听到
    // watch(sum, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, {immediate: true})

    // 监听对象类型时,如果这样写会监听不到salary改变,因为Impl对象的value是Proxy(reactive),内容改变时地址并未发生改变所以监听不到,有两种方案,下面演示
    // watch(person, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, {immediate: true})

    // 第一种方案, 监听person.value,因为是reactive实现的,所以默认开启深度监视会监听到
    // watch(person.value, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, {immediate: true})

    // 第二种方案, 开启深度监视会监听到, 这种方案更佳
    watch(person, (newValue, oldValue) => {
      console.log(newValue, oldValue);
    }, { immediate: true, deep: true })

    return {
      sum,
      msg,
      person
    }
  }
}
</script>

4. watchEffect函数(与watch对比)

watchEffect函数(初始化页面就会触发一次)
1. watch的套路是:既要指明监视的属性,也要指明监视的回调
2. watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
3. watchEffect有点像computed:
    3.1 但computed注重的是计算出来的值(回调函数的返回值),所以必须要写返回值
    3.2 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值

具体案例代码如下:
<template>
  <div>{{ sum }}</div>
  <button @click="sum++">sum按钮</button>
  <div>{{ msg }}</div>
  <button @click="msg += `!`">msg按钮</button>
  <hr />

  <div>{{ person.name }}</div>
  <button @click="person.name += '~'">按钮name</button>
  <div>{{ person.job.j1.salary }}</div>
  <button @click="person.job.j1.salary++">按钮salary</button>
</template>

<script>
import { reactive, ref, watchEffect } from 'vue'

export default {
  name: 'DemoComponent',
  setup() {
    let sum = ref(0);
    let msg = ref('你好啊')

    let person = reactive({
      name: '张三',
      job: {
        j1: {
          salary: 20
        }
      }
    })

    // 用了谁就监视谁
    watchEffect(() => {
      const x1 = sum.value;
      const x2 = person.job.j1.salary;
      console.log('我触发了', x1, x2);
    })

    // watch监视写法, 与上方watchEffect作对比
    // watch(person, (newValue, oldValue) => {
    //   console.log(newValue, oldValue);
    // }, {})

    return {
      sum,
      msg,
      person
    }
  }
}
</script>

文章来源:https://blog.csdn.net/weixin_50236973/article/details/134958157
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。