计算属性,watch和watchEffect

news2024/12/24 10:14:32

计算属性-computed 

什么是计算属性: computed函数,是用来定义计算属性的,计算属性不能修改。

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。

计算属性还可以依赖多个Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新。

methods和computed看起来都可以实现我们的功能, 那么为什么还要多一个计算属性这个东西呢? 原因:计算属性会进行缓存,如果多次使用时,计算属性只会调用一次;而方法会使用一次则调用一次,因此计算属性相对而言性能更好。

vue2:

computed:{
  sum(){
  return this.num1+ this.num2
  }
}

vue3的简单使用:

<template>
  <div>
    <div>计算属性</div>
    <hr>
    <button @click='age=25'>点击</button>
    <div>今年:{{age}}岁了</div>
    <div>明年:{{nextAge}}岁了</div>
  </div>
</template>
​
<script>
import { ref, computed } from 'vue'
​
export default { 
  setup () {
    // 计算属性:简化模板
    // 应用场景:基于已有的数据,计算一种数据
    const age = ref(18)
​
    // 计算属性基本使用
    const nextAge = computed(() => {
      // 回调函数必须return,结果就是计算的结果
      // 如果计算属性依赖的数据发生变化,那么会重新计算
      return age.value + 1
    })
​
    return { age, nextAge }
  }
}
</script> 

总结:Vue3中计算属性也是组合API风格

  1. 回调函数必须return,结果就是计算的结果

  2. 如果计算属性依赖的数据发生变化,那么会重新计算

  3. 不要在计算中中进行异步操作

高级:computed有两个方法,分别是set()和get()。

<template>
  <div>
    <div>计算属性</div>
    <hr>
    <button @click='age=25'>点击</button>
    <button @click='nextAge=28'>点击修改</button>
    <div>今年:{{age}}岁了</div>
    <div>明年:{{nextAge}}岁了</div>
  </div>
</template>
​
<script>
import { ref, computed } from 'vue'
​
export default {
  name: 'App',
  setup () {
    // 计算属性:简化模板
    // 应用场景:基于已有的数据,计算一种数据
    const age = ref(18)
​
    // // 计算属性基本使用
    // const nextAge = computed(() => {
    //   // 回调函数必须return,结果就是计算的结果
    //   // 如果计算属性依赖的数据发生变化,那么会重新计算
    //   return age.value + 1
    // })
​
    // 修改计算属性的值
    const nextAge = computed({
      get () {
        // 如果读取计算属性的值,默认调用get方法
        return age.value + 1
      },
      set (v) {
        // v是计算属性下传递的实参
        // 如果要想修改计算属性的值,默认调用set方法
        age.value = v - 1
      }
    })
​
    return { age, nextAge }
  }
}
</script>
​
<style lang="less">
</style>
​

总结:

  1. 计算属性可以直接读取或者修改

  2. 如果要实现计算属性的修改操作,那么computed的实参应该是对象

  • 读取数据触发get方法

  • 修改数据触发set方法,set函数的形参就是你赋给他的值

vue2和vue3组合式api

在vue2中如何组织代码的我们会在一个vue文件中methods,computed,watch,data中等等定义属性和方法,共同处理页面逻辑,

我们称这种方式为Options API

缺点: 一个功能往往需要在不同的vue配置项中定义属性和方法,比较分散,项目小还好,清晰明了,但是项目大了后,一个methods中可能包含20多个方法你往往分不清哪个方法对应着哪个功能

 

vue3中的Composition API就是用来解决这个问题的

在vue3 Composition API 中,我们的代码是根据逻辑功能来组织的,一个功能所定义的所有api会放在一起(更加的高内聚,低耦合),这样做,即时项目很大,功能很多,我们都能快速的定位到这个功能所用到的所有API,而不像vue2 Options API 中一个功能所用到的API都是分散的,需要改动功能,到处找API的过程是很费劲的

 

 

vue3之watch和watchEffect实战总结

watchwatchEffect都是vue3中的监听器,但是在写法和使用上是有区别的,主要是介绍一下watchwatchEffect的使用方法以及他们之间的区别。

watch 的工作原理:侦听特定的数据源,并在回调函数中执行副作用。它默认是惰性的——只有当被侦听的源发生变化时才执行回调,不过,可以通过配置 immediate 为 true 来指定初始时立即执行第一次。可以通过配置 deep 为 true,来指定深度监视。

immdiate: 默认情况下,侦听器需要 data 后面值改变了才会生效,若需要侦听器一进入页面就生效,那就需要使用 immediate。 deep: 默认情况下,侦听器只会监听数据本身的改变,若要进行深度监听,那就需要使用 deep。 immediate 和 deep 配置在第三个参数对象里。

第一个参数:监听谁,第二个参数:回调函数,第三个参数:配置对象

watch监听单个数据

<template><input type="text" v-model="text1" />
</template>
​
<script setup> 
import { ref, watch } from 'vue'
const text1 = ref('')
​
watch(text1, (newVal, oldVal) => {
console.log('监听单个数据', newVal, oldVal)
}) 
</script> 

监听多个数据(初始值为空,并没有进行打印)

<template>
    <input type="text" v-model="text1" placeholder="text1值" />
    <hr /> 
    <input type="text" v-model="text2" placeholder="text2值" /> 
</template> 
<script setup>
import { ref, watch, reactive } from 'vue'
const text1 = ref('') 
const text2 = ref('')  
watch([text1,text2], (newValue, oldValue) => {
    console.log('监听一组数据变化', newValue, oldValue)
})
​
// { immediate: true }
</script> 

坑:

1.监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)

<template>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>薪资:{{ person.job.j1.salary }}K</h2>
    <button @click="person.name += '~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>
​
    <hr />
    <input type="text" v-model="text1" />
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        //数据 
        let person = reactive({
            name: '张三',
            age: 18,
            job: {
                j1: {
                    salary: 20
                }
            }
        })
        const text1 = ref('')
        /* 情况三:监视reactive所定义的一个响应式数据的全部属性
                       1.注意:此处无法正确的获取oldValue
                       2.注意:强制开启了深度监视(deep配置无效)-不管嵌套有多深
           */
        watch(person, (newValue, oldValue) => {
            console.log('person变化了', newValue, oldValue)
        }, { deep: false }) //此处的deep配置无效 */
​
        watch(text1, (newVal, oldVal) => {
            console.log('监听单个数据', newVal, oldVal)
        })
        //返回一个对象(常用)
        return {
            person, text1
        }
    }
}
</script>
   

2.监视reactive定义的响应式数据中某个属性时:deep配置有效

<template>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>薪资:{{ person.job.j1.salary }}K</h2>
    <button @click="person.name += '~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button> 
    <hr />
    <input type="text" v-model="text1" />
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        //数据 
        let person = reactive({
            name: '张三',
            age: 18,
            job: {
                j1: {
                    salary: 20
                }
            }
        })
        const text1 = ref('')
        /* 情况三:监视reactive所定义的一个响应式数据的全部属性
                       1.注意:此处无法正确的获取oldValue
                       2.注意:强制开启了深度监视(deep配置无效)-不管嵌套有多深
           */
        watch(person, (newValue, oldValue) => {
            console.log('person变化了', newValue, oldValue)
        }, { deep: false }) //此处的deep配置无效 */

        watch(text1, (newVal, oldVal) => {
            console.log('监听单个数据', newVal, oldVal)
        })
        watch(() => person.age, (newValue, oldValue) => {
            console.log('person的age变化了', newValue, oldValue)
        }, { deep: true }) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
        //返回一个对象(常用)
        return {
            person, text1
        }
    }
}
</script>

使用ref定义数组时:(触发changeArr的时候,监听不到)

<template>
    <button @click="changeArr">按钮</button>
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        const array = ref([1, 2, 3]);
        
        const changeArr = () => {
            console.log('触发');
            array.value = [];
        }
        
        watch(array.value, (now, old) => {
            console.log(now, old); // 触发changeArr的时候,监听不到
        })

        return {
            array, changeArr
        }
    }
}
</script>

解决方案:

<template>
    <button @click="changeArr">按钮</button>
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        const array = ref([1, 2, 3]);
        const changeArr = () => {
            console.log('触发');
            array.value = [];
        }
        
        // watch(array.value, (now, old) => {
        //     console.log(now, old); // 触发changeArr的时候,监听不到
        // })

        watch(() => [array.value], (now, old) => {
            console.log(now, old)
        })


        return {
            array, changeArr
        }
    }
}
</script>

watchEffect

watchEffect 函数的特点:

  • 优点:

    • 会自动收集依赖,不需要手动传递侦听内容——自动侦听回调函数中使用到的响应式数据。

    • 默认 immdiate 是 true,所以初始化时会立即执行。

  • 缺点:

    • 无法获得变化前的值(oldVal)。

watch() 是懒执行的:当数据源发生变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。

watchEffect相当于将watch 的依赖源和回调函数合并,当任何你有用到的响应式依赖更新时,该回调函数便会重新执行。不同于 watchwatchEffect 的回调函数会被立即执行(即 { immediate: true }

简单来说,watchEffect 是 Vue3 中的一个响应式 API,它允许你监听响应式状态的变化,并在其发生变化时触发副作用函数。这个特性非常有用,在我们需要对响应式数据进行操作的时候,我们可以在监听到变化后马上做出反应。

举例:

<template>
name: <input type="text" v-model="student.name" />
age: <input type="number" v-model="student.age" />
</template>

<script setup>

import { reactive, watchEffect } from 'vue'

const student = reactive({name: '',age: ''
})
watchEffect(() => 
{console.log('name: ',student.name, 'age: ', student.age)
}) 

</script> 

watcheffect停止监听

<template>
    <div>
        <input type="text" v-model="obj.name">
        <button @click="stopWatchEffect">停止监听</button>
    </div>
</template>
  
<script>
import { reactive, watchEffect } from 'vue';
export default {
    setup() {
        let obj = reactive({
            name: 'zs'
        });
        
        const stop = watchEffect(() => {
            console.log('name:', obj.name)
        })
        
        const stopWatchEffect = () => {
            console.log('停止监听')
            stop();
        }

        return {
            obj,
            stopWatchEffect,
        }
    }
}
</script> 

watchEffect的副作用

什么是副作用(side effect),简单的说副作用就是执行某种操作,如对外部可变数据或变量的修改,外部接口的调用等。watchEffect的回调函数就是一个副作用函数,因为我们使用watchEffect就是侦听到依赖的变化后执行某些操作。

Vue3watchEffect侦听副作用传入的函数可以接收一个 onInvalidate 函数作为入参,用来注册清理失效时的回调

当以下情况发生时,这个失效回调会被触发:

  • 副作用即将重新执行时(即依赖的值改变)

  • 侦听器被停止 (通过显示调用返回值停止侦听,或组件被卸载时隐式调用了停止侦听)

import { watchEffect, ref } from 'vue'

const count = ref(0)
watchEffect((onInvalidate) => {
  console.log(count.value)
  onInvalidate(() => {
    console.log('执行了onInvalidate')
  })
})

setTimeout(()=> {
  count.value++
}, 1000) 

上述代码打印的顺序为: 0 -> 执行了onInvalidate,最后执行 -> 1

分析:初始化时先打印count的值0, 然后由于定时器把count的值更新为1, 此时副作用即将重新执行,因此onInvalidate的回调函数会被触发,打印执行了onInvalidate,然后执行了副作用函数,打印count的值1

import { watchEffect, ref } from 'vue'

const count = ref(0)
const stop = watchEffect((onInvalidate) => {
  console.log(count.value)
  onInvalidate(() => {
    console.log('执行了onInvalidate')
  })
})

setTimeout(()=> {
  stop()
}, 1000)

上述代码:当我们显示执行stop函数停止侦听,此时也会触发onInvalidate的回调函数。同样,watchEffect所在的组件被卸载时会隐式调用stop函数停止侦听,故也能触发onInvalidate的回调函数。

【注意】:

watchEffect 会在 Vue3 开发中大量使用,这里说几个注意点:

  1. 如果有多个负效应,不要粘合在一起,建议写多个 watchEffect

watchEffect(() => {
  setTimeout(() => console.log(a.val + 1), 1000);
  setTimeout(() => console.log(b.val + 1), 1000);
});
//错误的

这两个 setTimeout 是两个不相关的效应,不需要同时监听 a 和 b,分开写吧

watchEffect(() => {
  setTimeout(() => console.log(a.val + 1), 1000);
});

watchEffect(() => {
  setTimeout(() => console.log(b.val + 1), 1000);
});

2.watchEffect 也可以放在其他生命周期函数内

onMounted(() => {
  watchEffect(() => {
    // access the DOM or template refs
  });
}

利用watchEffect的非惰性执行,以及传入的onInvalidate 函数,我们可以做什么事情了?

场景:平时我们定义一个定时器,或者监听某个事件,我们需要在mounted生命周期钩子函数内定义或者注册,然后组件销毁之前在beforeUnmount钩子函数里清除定时器或取消监听。这样做我们的逻辑被分散在两个生命周期,不利于维护和阅读。

如果我利用watchEffect,创造和销毁逻辑放在了一起,此时代码更加优雅易读~

 

 

总结

watch 懒执行副作用——需要手动指明侦听的内容,也要指明侦听的回调。 默认 immdiate 是 false,所以初始化时不会执行,仅在侦听的源数据变更时才执行回调。 不需要有返回值。 可以获得变化前的值(oldVal)。 watchEffect 自动收集依赖,不需要手动传递侦听内容——自动侦听回调函数中使用到的响应式数据 默认 immdiate 是 true,所以初始化时会立即执行,同时源数据变更时也会执行回调。 不需要有返回值。 无法获得变化前的值(oldVal)。 computed 注重的计算出来的值(回调函数的返回值), 所以必须要写返回值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【目标检测论文阅读笔记】Extended Feature Pyramid Network for Small Object Detection

&#xff08;未找到代码&#xff0c;只有yaml文件&#xff09; Abstract. 小目标检测仍然是一个未解决的挑战&#xff0c;因为很难提取只有几个像素的小物体的信息。虽然特征金字塔网络中的尺度级对应检测缓解了这个问题&#xff0c;但我们发现各种尺度的特征耦合仍然会损害小…

百度飞桨paddlespeech实现小程序实时语音流识别

前言&#xff1a; 哈哈&#xff0c;这是我2023年4月份的公司作业。如果仅仅是简单的语音识别倒也没什么难度&#xff0c;wav文件直接走模型输出结果的事。可是注意标题&#xff0c;流式识别、实时&#xff01; 那么不得不说一下流式的优点了。 1、解决内存溢出的烦恼。 2、…

《论文阅读》Unified Named Entity Recognition as Word-Word Relation Classification

总结 将NER视作是word-word间的 Relation Classification。 这个word-word 间的工作就很像是TPlinker那个工作&#xff0c;那篇工作是使用token间的 link。推荐指数&#xff1a;★★★☆☆值得学习的点&#xff1a; &#xff08;1&#xff09;用关系抽取的方法做NER抽取 &…

佳明手表APP开发系列01——简单汉化英文版

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、佳明手表APP开发过程简介二、做个简单的个性化——在英文版写几个汉字1.MonkeyC 图形处理2.获得汉字点阵字模数据3.MonkeyC 汉字输出函数总结前言 佳明手表…

蓝海创意云应邀参与苏州市元宇宙生态大会

4月14日&#xff0c;苏州市软件行业协会元宇宙专委会成立大会暨元宇宙生态大会在苏成功举办。此次大会由苏州市工业和信息化局指导&#xff0c;苏州高新区&#xff08;虎丘区&#xff09;经济发展委员会、苏州市软件行业协会主办&#xff0c;蓝海彤翔集团作为协办单位参与此次大…

IDEA集成Git、GitHub、Gitee

一、IDEA 集成 Git 1.1、配置 Git 忽略文件 为什么要忽略他们&#xff1f; 与项目的实际功能无关&#xff0c;不参与服务器上部署运行。把它们忽略掉能够屏蔽 IDE 工具之间的差异。 怎么忽略&#xff1f; 创建忽略规则文件 xxxx.ignore&#xff08;前缀名随便起&#xff0c…

创建Google play开发者账号,并验证身份通过

一、注册前准备 最好准备一台没有怎么用过Google的电脑和&#x1fa9c;准备一个没有注册过Google的手机号准备一张信用卡或者借记卡&#xff08;需要支付$25&#xff09;&#xff0c;支持的类型如下图 这里还需注意&#xff1a;最后账号注册成功还需要验证身份也就是实名认证&…

关于Python爬虫的一些总结

作为一名资深的爬虫工程师来说&#xff0c;把别人公开的一些合法数据通过爬虫手段实现汇总收集是一件很有成就的事情&#xff0c;其实这只是一种技术。 初始爬虫 问题&#xff1a; 什么是爬虫&#xff1f; 网络爬虫是一种按照一定的规则&#xff0c;自动地抓取网络信息的程…

动态规划算法OJ刷题(3)

CC19 分割回文串-ii 问题描述 给出一个字符串s&#xff0c;分割s使得分割出的每一个子串都是回文串。计算将字符串s分割成回文串的最小切割数。例如:给定字符串s“aab”&#xff0c;返回1&#xff0c;因为回文分割结果[“aa”,“b”]是切割一次生成的。 解题思路 方法1&…

计算机操作系统(第四版)第四章存储器管理—课后习题答案

1.为什么要配置层次存储器&#xff1f; &#xff08;1&#xff09;设置多个存储器可以使存储器两端的硬件能并行工作。 &#xff08;2&#xff09;采用多级存储系统,特别是Cache技术,这是一种减轻存储器带宽对系统性能影响的最佳结构方案。 &#xff08;3&#xff09;在微处理机…

《Java8实战》第5章 使用流

上一章已经体验到流让你从外部迭代转向内部迭代。 5.1 筛选 看如何选择流中的元素&#xff1a;用谓词筛选&#xff0c;筛选出各不相同的元素。 5.1.1 用谓词筛选 filter 方法&#xff0c;该操作会接受一个谓词&#xff08;一个返回boolean 的函数&#xff09;作为参数&am…

MySQL数据库:聚合函数、分组查询、约束、默认值设置、自增属性

一、聚合函数 1.聚合函数 在MySQL数据库中预定义好的一些数据统计函数。 2.count(*) 功能&#xff1a;统计结果条数。 3.sum(字段名) 功能&#xff1a;对指定字段的数据求和。 4.avg(字段名) 功能&#xff1a;对指定字段的数据求平均值。 5.max(字段名) 和 min(字段名) …

正则化的基本认识

正则化(一) 拟合与欠拟合(二) 正则化的目的(三) 惩罚项&#xff08;3.1&#xff09;常用的惩罚项&#xff1a;&#xff08;3.2&#xff09;L-P范数&#xff1a;&#xff08;3.3&#xff09;L1与L2的选择&#xff1a;(一) 拟合与欠拟合 欠拟合&#xff1a; 是指测试级与训练集都…

docker目录映射

docker 常用命令 docker ps // 查看所有正在运行容器 docker stop containerId // containerId 是容器的ID docker ps -a // 查看所有容器 $ docker ps -a -q // 查看所有容器ID docker stop $(docker ps -a -q) // stop停止所有容器 docker rm $(docker ps -a -q) // remove删…

受害者有罪论——如何反驳

目录 一、那些「受害者有罪论」的说法 二、「受害者有罪论」的潜台词 三、如何反驳 反驳1&#xff1a;让受害者有罪论者感同身受 反驳2&#xff1a;说理 反驳3&#xff1a; 直接指出结论的错误 反驳4&#xff1a;与对方无关&#xff0c;不用多费唇舌 四、罪犯就是罪犯&…

golang-gin框架入门

基础 快速入门 gin完整支持路由框架支持全局异常&#xff08;错误&#xff09;处理内置渲染高可扩展 组件 在gin框架中四个基本组件是&#xff1a; Engine&#xff1a;是web server的根数据结构&#xff0c;也是基础容器&#xff1b;它包含复用器、中间件和配置设置。类似S…

GC 垃圾回收算法、垃圾回收器及 JVM 调优【JVM知识点-resu】

JVM知识点 详情请见&#xff1a;垃圾回收算法、垃圾收集器详情请见&#xff1a;JVM调优 1 GC垃圾回收算法 众所周知&#xff0c;Java的内存管理是交由了JVM&#xff0c;那么程序时时刻刻都在产生新对象&#xff0c;为了避免内存溢出&#xff0c;此时必然会涉及到垃圾回收&…

【MySQL数据库原理】Python3.7 中连接 MySQL 数据库

目录 1、安装mysql-connector-python2、连接 MySQL 数据库3、修改数据库1、安装mysql-connector-python 要在 Python 中连接 MySQL 数据库 “test”,可以使用 “mysql-connector-python” 包。首先,确保已经安装了该包。可以使用 pip 命令进行安装: pip install mysql-con…

[abc复盘] abc297 20230409

[atc复盘] abc297 20230409 一、本周周赛总结A - Double Click1. 题目描述2. 思路分析3. 代码实现B - chess9601. 题目描述2. 思路分析3. 代码实现C - PC on the Table1. 题目描述2. 思路分析3. 代码实现D - Count Subtractions1. 题目描述2. 思路分析3. 代码实现E - Kth Takoy…

Spring 04 -SpringAOP开发

SpringAOP开发SpringAOP1 原理2 动态代理2.1 JDK动态代理2.2.2 Cglib动态代理2.2.3 **JDK动态代理和Cglib动态代理**3 SpringAOP3.1 AOP专业术语3.2 环境搭建3.3 基于XML配置3.4 基于注解配置2.5 通知类型面向切面编程&#xff0c;在不修改源代码的情况加&#xff0c;对类功能实…