【Vue】深究计算和侦听属性的原理

news2024/7/5 0:28:37

hello,我是小索奇,精心制作的Vue系列教程持续更新哈,涵盖大量的经验和示例,由浅入深进行讲解,想要学习&巩固&避坑就一起学习吧~

计算和侦听属性

计算属性

重点概要

定义:要用的属性不存在,需要通过已有属性计算得来

原理:底层借助了Objcet.defineproperty()方法提供的getter和setter来计算属性计算属性会自动找到getter并调用,拿到返回值放到VM身上

关于get函数

  • get初次读取时会执行一次

  • 当依赖的数据发生改变时会被再次调用

  • 与methods实现相比,内部有缓存机制,当我们再次调用get时,直接走缓存了,效率更高,调试时也直接显示computed

那么我们需要改值的时候呢?

  • 计算属性最终会出现在VM上,利用this进行读取使用即可

  • 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变

  • 如果计算属性确定不考虑修改,可以使用计算属性的简写形式

代码案例

<body>
    <div id="root">
    
        <input type="text" v-model="firstName"> <br/><br/>
        <input type="text" v-model="lastName" > <br/><br/>
        <h1>{{name}}</h1>
    </div>
   <script>
    Vue.config.productionTip = false
       const vm = new Vue({
            el:'#root',
            data:{
                firstName:'即兴',
                lastName:'小索奇'
            },
            computed:{
                name:{
                    get(){
       return this.firstName + '-' + this.lastName
                  
                    set(value){
                        console.log(VM)
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }
            }
        })
   </script>
</body>

image-20230819013138164

image-20230819013138164

<body>
    <div id="root">
    
            <input type="text" v-model="firstName"> <br/><br/>
         <input type="text" v-model="lastName"> <br/><br/>
            <h1>{{name}}</h1>
    </div>
   <script>
    Vue.config.productionTip = false
       const vm = new Vue({
            el:'#root',
            data:{
                firstName:'即兴',
                lastName:'小索奇'
            },
            computed:{
                name:{
                    get(){
                        return this.firstName + '-' + this.lastName
                    },
                    set(value){
                        // console.log(VM)
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr [1]
                    }
                }
            }
        })
   </script>
</body>

计算属性简写

  • 在实际应用过程中计算属性一般是仅读取展示,不修改的

  • 当你确定只读不更改,那么才可以用简写函数

执行流程:执行完name函数,往VM身上放name这个属性,它的值是函数返回的结果

 computed:{
          name(){
             console.log('简写形式,等同于get ')
             return this.firstName + '-' + this.lastName
           }, 
         }

调用时用name即可不用加括号name()-> x

拓展

还可以方法调用,为什么不用呢?看下例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/JS" src="./js/vue.js"></script>
</head>
<body>
    <div id="root">
    
        <input type="text" v-bind:value="firstName"> <br><br>
        <input type="text" :value="lastName" ><br><br>
        <button> 
            <h1>{{name()}}</h1>
        </button>
    </div>
   <script>
    Vue.config.productionTip = false
        new Vue({
            el:'#root',
            data:{
                firstName:'即兴',
                lastName:'小索奇'
            },
            methods:{
                name(){
                    return this.firstName + this.lastName
                }
                
            }
        })
   </script>
</body>
</html>

为什么不用?

因为这样更新频率极高,每一次更改值都会重新调用方法解析模板;效率低下

侦听属性

  • 侦听属性称为监视属性也是一样的

在Vue.js中,侦听属性通常是通过"监视器"(Watchers)来实现的监视器允许你在Vue实例中监听一个特定的数据属性,然后在属性值发生变化时执行相应的逻辑这可以用来在属性变化时执行异步操作、更新其他数据,或者触发其他行为

当被监视的属性变化时,回调函数自动调用

侦听属性的定义方式有两种:声明式和编程式下面详细解释这两种方式以及如何使用侦听属性:

1. 侦听属性:

watch选项来对一个或多个侦听属性每个侦听属性都对应一个属性名,以及一个处理函数,当这个属性发生变化时,处理函数会被触发

<body>
  <div id="root">
    <h2>今天天气很{{ info }}</h2>
    <button @click="changeWeather">切换天气</button>
  </div>
</body>

<script type="text/JS">
  Vue.config.productionTip = false;

  const vm = new Vue({
    el: '#root',
    data: {
      isHot: true,
    },
    computed: {
      info() {
        return this.isHot ? '炎热' : '凉爽';
      },
    },
    methods: {
      changeWeather() {
        this.isHot = !this.isHot;
      },
    },
  });
  watch:{
  isHot:{
   immediate:true, 
   handler(newValue,oldValue){
   console.log('isHot被修改了',newValue,oldValue)
    }
   }
  } 
</script>

2. 侦听属性:

还可以通过$watch方法在Vue实例中编程式地设置侦听属性 ,调用VM的方法$watch

  vm.$watch('isHot', {
  // 初始化立即执行handler
    immediate: true,
    // 同理,都能接受新旧值进行处理
    handler(newValue, oldValue) {
      console.log('isHot被修改了', newValue, oldValue);
    },
  });

无论是声明式还是编程式的侦听属性,你都可以在侦听属性的处理函数中执行任何你需要的操作,比如发起网络请求、更新其他数据属性、触发方法等

需要注意的是,尽管侦听属性是强大的工具,但过多的侦听属性可能会导致代码变得复杂且难以维护在一些情况下,你可以使用计算属性(Computed Properties)来取代侦听属性,以提高代码的可读性和性能

使用watch选项或$watch方法都可以设置侦听属性,从而在属性变化时触发处理函数

深度监视

简单概括就是,深度监视是指对一个对象的所有嵌套属性进行观察和监听

  1. 使用方法:在 watch 选项中,为要监视的对象设置 deep: true

  2. 工作原理:当设置为 deep: true 时,Vue 会递归地遍历对象的所有子属性,确保无论如何修改对象的任何嵌套属性,都会触发回调函数

  3. 注意事项:因为深度监视需要递归地监听对象的所有子属性,所以它可能会对性能产生影响,特别是当对象结构复杂、嵌套层次深时

  4. 使用场景:当你需要响应对象内部属性的变化,而不仅仅是对象本身的引用变化时,使用深度监视

一个小案例

   <body>
  <div id="root">
   <h2>今天天气很{{info}}</h2>
   <button @click="changeWeather">切换天气</button>
   <hr/>
   <h3>a的值是:{{numbers.a}}</h3>
   <button @click="numbers.a++">点我让a+1</button>
   <h3>b的值是:{{numbers.b}}</h3>
   <button @click="numbers.b++">点我让b+1</button>
   <button @click="numbers = {a:666,b:888}">改变numbers对象</button>
   {{numbers.c.d.e}}
  </div>
 </body>

 <script type="text/JS">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
  
  const vm = new Vue({
   el:'#root',
   data:{
    isHot:true,
    numbers:{
     a:1,
     b:1,
     c:{
      d:{
       e:100
      }
     }
    }
   },
   computed:{
    info(){
     return this.isHot ? '炎热' : '凉爽'
    }
   },
   methods: {
    changeWeather(){
     this.isHot = !this.isHot
    }
   },
   watch:{
    isHot:{
     handler(newValue,oldValue){
      console.log('isHot被修改了',newValue,oldValue)
     }
    },
    //监视多级结构中某个属性的变化
    /* 'numbers.a':{
     handler(){
      console.log('a被改变了')
     }
    } */
    //监视多级结构中所有属性的变化
    numbers:{
     deep:true,
     handler(){
      console.log('numbers改变了')
     }
    }
   }
  })

 </script>
</html>

注意:当彻底替换掉numbers的时候,是没有d的,打开调试页面,所以点击彻底替换之后d会报错

deep:true这一项不开启的话,当numbers中的项(如a、b改变)number不会变化,当我们开启的话,就代表监视多级结构中属性的变化

侦听属性简写

  • 当配置项中只有handler时才可以简写,要是需要其它配置的话(比如deep)则不能够简写(一般默认写这个即可)

watch: {
  isHot(newValue, oldValue) {
    console.log('isHot被修改了', newValue, oldValue)  
  }
}

使用VM方法调用

//正常写法
  /* vm.$watch('isHot',{
   immediate:true, //初始化时让handler调用一下
   deep:true,//深度监视
   handler(newValue,oldValue){
    console.log('isHot被修改了',newValue,oldValue)
   }
  }) */

  //简写
  /* vm.$watch('isHot',(newValue,oldValue)=>{
   console.log('isHot被修改了',newValue,oldValue,this)
  }) */

对比侦听属性 & 计算属性

计算属性主要适用于:

  • 需要对数据进行转换或格式化后再显示

  • 需要使用多个数据计算得出一个结果进行显示

  • 需要缓存结果,避免每次重复计算

  • 浮动面板或列表中需要对每个元素做重复计算

侦听属性主要适用于:

  • 需要在数据变化时触发副作用,比如调用接口、导航路由等(后期会提到)

  • 需要进行异步操作或开销较大的处理(比如使用定时器)

  • 需要参数化或复用监听逻辑

  • 当值的变化需要改变多个状态时

简单来说,如果单纯显示或格式化数据,使用计算属性可以简化代码并获得性能优势

如果数据变化需要触发复杂逻辑或副作用,监听属性会更合适

如果一个业务逻辑这两种都能实现的话,优先考虑计算属性

拓展

下列代码的this输出什么?

   watch:{
            setTimeout(()=>{
                this.name = this.firstName + '-' + this.lastName
            },1000)
        }

这里的this指向Vue实例

Q:如果把setTimeOut剪头函数改为普通函数即:setTimeout(function(){}),那么this指向是哪里

A:指向window!如果定时器是JS引擎调用的,箭头函数没有自己的this指向,那么就会往外找,从而找到VM

具体来说普通函数定义的方法,它的 this 会绑定当前 Vue 实例

tips

  • computed能完成的功能,watch都可以完成

  • watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作,上面定时器例子就阐明了这一点

两个重要的小原则:

  • 被Vue管理的函数,最好写成普通函数,这样this的指向才是VM 或 组件实例对象,可以更好的调用VM

  • 不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,this的指向也就不会乱套了

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

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

相关文章

3战略设计

产品代码都给你看了&#xff0c;可别再说不会DDD&#xff08;三&#xff09;&#xff1a;战略设计 # 这是一个讲解DDD落地的文章系列&#xff0c;作者是《实现领域驱动设计》的译者滕云。本文章系列以一个真实的并已成功上线的软件项目——码如云&#xff08;https://www.mryq…

产品经理认证(UCPM)备考心得

UCPM是联合国训练所CIFAL中心颁发的产品经理证书。如今&#xff0c;ESG是推动企业可持续发展的新潮流。UCPM作为一种可持续发展证书&#xff0c;为我们带来了一套先进科学、系统全面的产品管理模式&#xff0c;是产品管理领域公认的权威证书。那么&#xff0c;如何准备这张证书…

MySQL中explain各字段详解及举例

MySQL版本&#xff1a;8.0.33 建表语句&#xff1a; DROP TABLE IF EXISTS actor; CREATE TABLE actor (id int(11) NOT NULL,name varchar(45) DEFAULT NULL,update_time datetime DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;INSERT INTO actor (i…

AxureRP制作静态站点发布互联网,实现公网访问【内网穿透】

AxureRP制作静态站点发布互联网&#xff0c;内网穿透实现公网访问 文章目录 AxureRP制作静态站点发布互联网&#xff0c;内网穿透实现公网访问前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4…

力扣-290.单词规律

Idea 先建立一个hashmap&#xff0c;记录s串中的每个单词以及对应的下标再建立一个hashmap&#xff0c;记录pattern串中相同字母以及对应的下标遍历pattern串时&#xff0c;遇到不同字母存到pat表中&#xff0c;同时将下标对应的s中的单词存入到查重test集中&#xff0c;因为如…

2023年8月京东洗烘套装行业品牌销售排行榜(京东数据开放平台)

鲸参谋监测的京东平台8月份洗烘套装市场销售数据已出炉&#xff01; 根据鲸参谋平台的数据显示&#xff0c;今年8月份&#xff0c;京东平台洗烘套装的销量为1.1万&#xff0c;同比增长约218%&#xff1b;销售额约为1.2亿&#xff0c;同比增长约279%。可以看到&#xff0c;洗烘…

零基础学前端(七)将HTML+CSS静态页面 发布成网站

我们学习了HTML和CSS&#xff0c;已经可以做出精美的静态网页。我们不慌学习JavaScript&#xff0c;因为Javascript的作用是为网页增加动作和数据交换&#xff0c;只能让网页更完美而已&#xff0c;现在网页的基础我们已经可以搭建&#xff0c;我们不妨先将网站发布出去&#x…

【C语言】——自定义类型详解:结构体,枚举,联合

大家好&#xff0c;今天为大家分享一下C语言中的那些自定义类型&#xff1a;结构体&#xff0c;枚举&#xff0c;联合&#xff0c;还有之前可能不曾了解的结构体内存对齐、位段等知识点&#xff01;&#xff01;&#xff01; 一、结构体 结构是一些值的集合&#xff0c;这些值称…

【C++】String类基本接口介绍(多看英文文档)

string目录 目录 如果你很赶时间&#xff0c;那么就直接看我本标题下的内容即可&#xff01;&#xff01; 一、STL简介 1.1什么是STL 1.2STL版本 1.3STL六大组件 1.4STL重要性 1.5如何学习STL 二、什么是string&#xff1f;&#xff1f;&#xff08;本质上是一个类&…

研究铜互连的规模能扩大到什么程度

随着领先的芯片制造商继续将finFET以及很快的纳米片晶体管缩小到越来越小的间距&#xff0c;使用铜及其衬垫和阻挡金属&#xff0c;较小的金属线将变得难以维持。接下来会发生什么以及何时发生&#xff0c;仍有待确定。 自从IBM在20世纪90年代向业界引入采用双镶嵌工艺的铜互连…

mysql四种事务隔离级别介绍

MySQL事务隔离级别定义了不同事务之间的隔离程度。MySQL标准列表了四个隔离级别&#xff0c;依次为读未提交&#xff08;READ UNCOMMITTED&#xff09;、读已提交&#xff08;READ COMMITTED&#xff09;、可重复读&#xff08;REPEATABLE READ&#xff09;和串行化&#xff08…

会务转化如何取得“数字化”突破?会务营销数字化功能推荐

​数字化时代下&#xff0c;企业日常的活动经营已经不再局限于简单的人员聚集和互动交流&#xff0c;而是需要更为标准化、专业化的会务系统&#xff0c;在对会务活动进行支撑和保障的同时&#xff0c;达成会务营销的更高转化和会务价值的更大输送。因此&#xff0c;企业需要选…

深度学习入门-0-简介与学习路线

一、简介 1.概述 深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中的一个研究方向&#xff0c;它被引入机器学习使其更接近于最初的目标——人工智能(AI, Artificial Intelligence)。 深度学习是学习样本数据的内在规律和表示层次&#xff0c;这些学习过程…

选择文件:文件选择框的代码触发【极易版】【文件上传功能】

最近业务中遇到添加附件功能&#xff0c;点击对应元素&#xff0c;在特定条件下触发文件选择&#xff0c;然后将选中的文件上传到后台。 文件上传是使用阿里云实现的&#xff0c;这里主要说文件选择功能。也就是怎样添加附件到界面上。 一 简单实现——点击按钮触发图片选择框…

【linux】实现shell

自我名言&#xff1a;只有努力&#xff0c;才能追逐梦想&#xff0c;只有努力&#xff0c;才不会欺骗自己。 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&#xff01; 如果发现内容有不对的地方欢迎在评论区批评指正&#xff0c;这是对我最大的鼓励&#xff01;&#xf…

对于现代互联网企业来说Python数据分析有什么用?

我们每一个人&#xff0c;每天无时无刻都在生产数据&#xff0c;一分钟内&#xff0c;微博上新发的数据量超过10万&#xff0c;b站的视频播放量超过600万……这些庞大的数字&#xff0c;意味着什么&#xff1f;意味着每天需要大量的人员要对这些数据进行分析&#xff0c;筛选有…

ssm+vue的教室信息管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的教室信息管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

OpenHarmony应用开发涉及的主要因素与UX设计规范

一、OpenHarmony应用开发涉及的主要因素 二、OpenHarmony应用开发UX设计规范 UX设计规范的主要内容与部分图标示例 2.OpenHarmony应用设计原则 设计原则&#xff0c;当为多种不同的设备开发应用时&#xff0c;有如下设计原则&#xff1a; 差异性&#xff0c;充分了解所要支…

LinearLayout里子view点击,其他空白间隙处禁止点击

LinearLayout里子view点击&#xff0c;其他空白间隙处禁止点击 经过不断摸索终于实现了。 像头条里黄色区域禁止点击实现。 可以通过在父 LinearLayout 上设置 android:clickable"true" 属性来实现&#xff0c;然后在子 View 上设置 android:clickable"false&…

1688-阿里巴巴批发网(获取商品的名称,价格,图片)

1688 item_get-获得1688商品详情 为了进行电商平台 的API开发&#xff0c;首先我们需要做下面几件事情。 1&#xff09;开发者注册一个账号 2&#xff09;然后为每个1688 应用注册一个应用程序键&#xff08;App Key) 。 3&#xff09;下载1688 API的SDK并掌握基本的API基础…