• Vue3中的computed和watch属性



    1. computed计算属性

    简写写法(只实现了 get ):

    <template>
      <div>
        <ul>
          <li v-for="item of carts" :key="item.id">
            {{ item.name }}
          li>
        ul>
        <hr />
        <h3>合计:{{ totalPrice }}h3>
      div>
    template>
    
    <script>
    import { computed, reactive, toRefs } from 'vue'
    export default {
      setup() {
        let state = reactive({
          carts: [
            { id: 1, name: '小米', price: 1, num: 1 },
            { id: 2, name: '大米', price: 1, num: 1 }
          ],
          total: 0
        })
    
        // 计算属性   -- get
        let totalPrice = computed(() => {
          return state.carts.reduce((p, { price, num }) => {
            p += price * num
            return p
          }, 0)
        })
    
        // let totalPrice = computed({
        //   get() {
        //     return state.carts.reduce((p, { price, num }) => {
        //       p += price * num
        //       return p
        //     }, 0)
        //   }
        // })
    
        return { ...toRefs(state), totalPrice }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    标准写法(可以实现 get 和 set 方法):

    <template>
      <div>
        <ul>
          <li v-for="item of carts" :key="item.id">
            {{ item.name }}
          li>
        ul>
        <hr />
        <h3>合计:{{ totalPrice }}h3>
      div>
    template>
    
    <script>
    import { computed, reactive, toRefs } from 'vue'
    export default {
      setup() {
        let state = reactive({
          carts: [
            { id: 1, name: '小米', price: 1, num: 1 },
            { id: 2, name: '大米', price: 1, num: 1 }
          ],
          total: 0
        })
    
        let totalPrice = computed({
          get() {
            return state.carts.reduce((p, { price, num }) => {
              p += price * num
              return p
            }, 0)
          },
          // 了解一下
          set(v) {
            console.log('set', v)
          }
        })
        // 如果你给计算属性赋值,则一定要写标准方式,set方法一定要写
        totalPrice.value = 'abc'
        return { ...toRefs(state), totalPrice }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    完整的购物车案例:

    <template>
      <div>
        <h3>{{ total }}h3>
        <ul>
          <li v-for="(item, index) of carts" :key="item.id">
            <span>{{ item.name }}span>
            <span>
              <button @click="setNum(index, 1)">+button>
              <button @click="totalPrice = { index, n: 1 }">另一种实现求和的方式button>
              <span>{{ item.num }}span>
              <button @click="setNum(index, -1)">-button>
            span>
          li>
        ul>
        <hr />
        <h3>合计:{{ totalPrice }}h3>
      div>
    template>
    
    <script>
    import { computed, reactive, toRefs } from 'vue'
    export default {
      setup() {
        let state = reactive({
          carts: [
            { id: 1, name: '小米', price: 1, num: 1 },
            { id: 2, name: '大米', price: 1, num: 1 }
          ],
          total: 0
        })
    
        let totalPrice = computed({
          get() {
            return state.carts.reduce((p, { price, num }) => {
              p += price * num
              return p
            }, 0)
          },
          // 求和方式2:
          set(v) {
            if (v.n) {
              state.carts[v.index].num += v.n
            }
          }
        })
    
        // 求和方式1:
        const setNum = (index, n) => {
          state.carts[index].num += n
          if (state.carts[index].num <= 1) state.carts[index].num = 1
          if (state.carts[index].num >= 10) state.carts[index].num = 10
        }
    
        return { ...toRefs(state), totalPrice, setNum }
      }
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    在这里插入图片描述

    2. watch侦听器属性

    • watchEffect 是自动去根据方法中的调用来确定依赖项。
    • watch 是手动指定依赖项 – 用它可能会多一些。

    2.1 watchEffect

    <template>
      <div>
        <h3>{{ num }}h3>
        
        <input type="text" v-model="name" />
        <button @click="num++">+++button>
        
      div>
    template>
    
    <script>
    // watchEffect 自动去根据方法中的调用来确定依赖项
    // watch 手动指定依赖项  -- 用它可能会多一些
    import { ref, watch, watchEffect } from 'vue'
    export default {
      setup() {
        const num = ref(100)
    
        const name = ref('')
    
        // 侦听,它必须要有依赖项
        // 它在初始化时,会主动执行1次,如果没有依赖项,则不会再次执行
        // watchEffect(() => {
        //   // 这里只会在初始时打印一次222
        //   console.log(222)
        // })
    
        watchEffect(() => {
          // 此时它的依赖项为 num变量,如果它有改变,则回调函数会自动触发
          // 它的依赖项可以是1到N个
          console.log(222, num.value)
        })
    
        return { num,name }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    在这里插入图片描述

    watchEffect 的返回值:

    <template>
      <div>
        <h3>{{ num }}h3>
        <button @click="num++">+++button>
        <button @click="stop">停止侦听button>
      div>
    template>
    
    <script>
    // watchEffect 自动去根据方法中的调用来确定依赖项
    // watch 手动指定依赖项  -- 用它可能会多一些
    import { ref, watch, watchEffect } from 'vue'
    export default {
      setup() {
        const num = ref(100)
    
        const stopHandle = watchEffect(() => {
          console.log(222, num.value)
        })
    
        const stop = () => stopHandle()
    
        return { num, stop }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    watchEffect 的 onCleanup 回调参数:

    watchEffect 还有一个回调参数,此参数它也是一个函数,作用是清理副作用。

    <template>
      <div>
        <h3>{{ num }}h3>
        <button @click="num++">+++button>
        <button @click="stop">停止侦听button>
      div>
    template>
    
    <script>
    // watchEffect 自动去根据方法中的调用来确定依赖项
    // watch 手动指定依赖项  -- 用它可能会多一些
    import { ref, watch, watchEffect } from 'vue'
    export default {
      setup() {
        const num = ref(100)
        let timer
    
        // 此方法它还有一个回调参数,此参数它也是一个函数,作用,清理副作用
        const stopHandle = watchEffect(
          onCleanup => {
            console.log(num.value)
            // console.log(222, num.value, name.value)
            onCleanup(() => {
              console.log('清理上一次的处理')
              timer && clearTimeout(timer)
            })
            timer = setTimeout(() => {
              console.log('输出的')
            }, 1000)
          },
          {
            // flush?: 'pre' | 'post' | 'sync';
            // pre 模板渲染之前触发
            // post 模板渲染之后触发
            // sync 和模板渲染同步来触发
            // 默认为 pres
            flush: 'pre'
          }
        )
    
        const stop = () => stopHandle()
    
        return { num, stop }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    在这里插入图片描述

    2.2 watch

    监听一个变量值的变化:

    <template>
      <div>
        <div>{{ num }} <button @click="num++">+++button>div>
        <input type="text" v-model="name" />
      div>
    template>
    
    <script>
    
    import { ref, watch } from 'vue'
    export default {
      setup() {
        const num = ref(100)
        const name = ref('')
    
        // 监听num变量它的变化,如果有变化,则触发
        watch(
          num,
          (newValue, oldValue) => {
            console.log(newValue)
          },
          {
            // 初始化执行1次,默认为false
            immediate: false
          }
        )
    
        return { num, name }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述

    监听多个变量值的变化:

    <template>
      <div>
        <div>{{ num }} <button @click="num++">+++button>div>
        <input type="text" v-model="name" />
      div>
    template>
    
    <script>
    import { ref, watch } from 'vue'
    export default {
      setup() {
        const num = ref(100)
        const name = ref('')
    
        // 以数组的方式来写,它可以监听多个变量的值的变化,回调参数为一个数组
        watch([num, name], (nArr, oArr) => {
          console.log(nArr)
        })
        // 在工作中,通常只关心新的值,所以只会写一个参数,就像下面这样
        // watch([num, name], ([numValue, nameValue]) => {
        //   console.log(numValue, nameValue)
        // })
    
        return { num, name }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    监听对象中具体的值:

    <template>
      <div>
        <input type="text" v-model="user.name" />
      div>
    template>
    
    <script>
    import { ref, watch } from 'vue'
    export default {
      setup() {
        const user = ref({ id: 1, name: '张三' })
    
        // 目前对于ref定义的引用类型,默认无法监听
        // watch(user, (n, o) => {
        //   console.log(n)
        // })
    
        // 但是可以指定监听对象中具体的值
        watch(
          // 'obj.name'(n,o){}
          () => user.value.name,
          (n, o) => {
            console.log(n)
          }
        )
    
        return { user }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    监听ref的引用对象(添加参数3):

    <template>
      <div>
        <input type="text" v-model="user.name" />
      div>
    template>
    
    <script>
    import { ref, watch } from 'vue'
    export default {
      setup() {
        const user = ref({ id: 1, name: '张三' })
    
        // 监听ref的引用对象 添加参数3
        watch(user, (n, o) => {
          console.log(n)
        },{
          deep:true
        })
    
        return { user }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    监听 reactive 定义的响应变量:

    <template>
      <div>
        <input type="text" v-model="user.name" />
      div>
    template>
    
    <script>
    import { reactive, watch } from 'vue'
    export default {
      setup() {
        const user = reactive({ id: 1, name: '张三' })
    
        // 监听的是一个reactive定义的响应变量,它默认就可以进行深层监听
        // 所以在工作中,如果你定义的值它是一个引用类型,建议使用reactive,基本类型用ref
        const stop = watch(user, (n, o) => {
          console.log(n)
        })
    
        return { user, stop }
      }
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

  • 相关阅读:
    【LWE问题简介】
    基于商用密码技术的铁路行业统计调查系统安全研究
    点云处理实战 PCL求解点云表面曲率
    【K8S专栏】Kubernetes工作负载管理
    二叉树中的topk问题(带图详解)
    vue2中watch监听的使用及immediate、handler和deep属性解读
    linux 中jenkins启动重启停止命令 改端口
    数据中台建设模式的4大趋势和3大重点总结全了
    正在等待操作系统重新启动。 请重新启动计算机以安装autocad 2024。
    抖音全接口API
  • 原文地址:https://blog.csdn.net/weixin_45605541/article/details/127982997