4.Vue-计算属性、监视属性、深度监视、计算属性与监视属性对比

目录

计算属性

一、计算属性

1.1 计算属性介绍

1.2 姓名案例

1.2.1 插值语法实现

1.2.2 计算属性实现

1.2.3 计算属性简写

1.3 监视天气案例

二、监视属性

2.1 监视属性

2.1.1 写法 ① watch

2.1.2 写法② vm.$watch

2.2 深度监视

2.2.1 监视多级结构中某个属性的变化

2.2.2 监视多级结构中所有属性的变化(深度监视)

2.3 监视属性简写

2.4 姓名案例

三、computed与watch对比


计算属性

一、计算属性

1.1 计算属性介绍

计算属性

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

一定是已有的属性,而不是已有的变量

原理:底层借助了Object.defineProperty方法提供的getter和setter

有关数据代理Object.defineProperty方法可以查看下面这篇文章:

2.Vue — 模板语法、数据绑定、el与data的写法、数据代理-CSDN博客


关键字computed

image-20231030161443184


get函数什么时候执行

  • 初次读取时会执行一次

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

这样就避免了实际值与缓存值不一样的情况(数据不一致)


优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

比如下面一段代码,计算属性fullName其实被调用了一次,而不是四次

全名:<span> {{fullName}}</span> <br/><br/>
全名:<span> {{fullName}}</span> <br/><br/> 
全名:<span> {{fullName}}</span> <br/><br/>
全名:<span> {{fullName}}</span> <br/><br/>

读取到上面的第一行代码时候发现有人读取了计算属性fullName了,于是调用了fullName的get方法,之后将get方法的返回值做了一个缓存

接下来的三行读取fullName的时候,便直接从缓存中读取

image-20231030162514469


备注

  • 计算属性最终会出现在vm上,直接读取使用即可

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


计算属性除了getter还有setter

假如说我们不设置setter的话,修改不了计算属性,会有下面这个错误

image-20231030163714811

// 一定要有setter函数么?不一定,如果确定数据只需要读的话,不需要setter函数
set(value){
  const arr=value.split('-')
  this.firstName=arr[0]
  this.lastName=arr[1]
}

1.2 姓名案例

有如下所示的文本框,当“姓”或“名”改变时,下面的全名也会改变,那怎么实现呢?

image-20231030135356592

1.2.1 插值语法实现

这一块有一个细节问题

我们修改了firstName和lastName,并没有修改“全名”,那全名为什么会随之改变呢?

当data中的任何一个数据发生变化的时候,Vue中的模板都会重新解析一遍

data中数据发生变化,模板重新发生解析

假如说firstName发生了改变,就会重新读取

如果我们在Vue模板中调用了方法,此时方法也会重新调用一下

简单的来说,由于firstName或lastName发生改变,引起了Vue模板的重新解析,然后会发现“全名”的值来自于一个函数的调用,然后Vue实例回去调用这个函数

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
           <!-- 容器 -->
           姓:<input type="text" v-model="firstName"><br/><br/>
           名:<input type="text" v-model="lastName"><br/><br/>
           全名:<span> {{fullName()}}</span>
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
            new Vue({
                el:'#root',
                data:{
                    firstName:'张',
                    lastName:'三'
                },
                methods:{
                    fullName(){
                        return this.firstName+'-'+this.lastName
                    }
                }
            })
 
        </script>   
    </body>
</html>

当我们的“姓”是“张”,“名”是“三”时,“全名”为“张三”

image-20231030153201245

当“姓”或“名”修改了后,“全名”也会跟着修改

image-20231030153353925

1.2.2 计算属性实现

此时firstName、lastName都会在vm._data中,但是vm实例对象中绝对没有计算属性fullName

fullName的出现是firstName、lastName计算出来直接丢在vm实例对象身上的


<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
           <!-- 容器 -->
           姓:<input type="text" v-model="firstName"><br/><br/>
           名:<input type="text" v-model="lastName"><br/><br/>
           全名:<span> {{fullName}}</span>
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
          const vm  =  new Vue({
                el:'#root',
                data:{
                    firstName:'张',
                    lastName:'三'
                },
               //计算属性 
                computed:{
                   fullName:{
                    // get有什么作用?当有人读取fullName时,get就会被调用,且返回值就会作为fullName的值
                    //get什么时候调用?1.初次读取fullName时  2.所依赖的数据发生变化时    
                    get(){
                        // 在这里面的this同样指向vm实例对象
                        return this.firstName+'-'+this.lastName
                    },
                    // 一定要有setter函数么?不一定,如果确定数据只需要读的话,不需要setter函数
                    set(value){
                        const arr=value.split('-')
                        this.firstName=arr[0]
                        this.lastName=arr[1]
                    }
                   }
                }
            })
 
        </script>   
    </body>
</html>

我们在获取firstName和lastName的时候,下面这样是获取不到firstName、lastName的

get(){
  // 在这里面的this同样指向vm实例对象
  return this.firstName+'-'+this.lastName
}

因为firstName、lastName是我们在data对象中定义的属性

image-20231030161857185

我们要从vm实例对象中获取

get(){
   // 在这里面的this同样指向vm实例对象
   return this.firstName+'-'+this.lastName
}

1.2.3 计算属性简写

什么时候能够使用计算属性的简写形式

只考虑读取,不考虑修改的时候

全名:<span> {{fullName}}</span>

下面fullName()函数全当fullName的getter函数使用

               //计算属性 
                computed:{
                    //简写之后不用再把fullName写成一个配置对象了
                    // 这个函数就当getter用  函数的名就是计算属性的名
                   fullName(){
               // 在这里面的this同样指向vm实例对象
                        return this.firstName+'-'+this.lastName
                   }
                }

1.3 监视天气案例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
            <h2>今天天气:{{info}}</h2>
            <button @click="changeWeather">切换天气</button>
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
            new Vue({
                el:'#root',
                data:{
                    isHot:true
                },
            computed:{
                info(){
                    return this.isHot ? '炎热':'凉爽'
                }
            },
            methods: {
                changeWeather(){
                    this.isHot = !this.isHot
                }
            },
            })
 
        </script>   
    </body>
</html>

当我们点击“切换天气”按钮时,下面的页面就会发生改变

image-20231030170014008

image-20231030170005154

二、监视属性

2.1 监视属性

监视属性:监视某一个属性的变化

关键字:watch

当被监视的属性发生变化时,回调函数自动调用,进行相关操作

监视的属性必须存在,才能进行监视

那能不能监视计算属性? 可以

比如下面我们将监视“isHot”属性的变化

2.1.1 写法 ① watch

    <script type="text/javascript">
        //阻止vue在启动时生成生产提示
        Vue.config.productionTip = false

        new Vue({
            el: '#root',
            data: {
                isHot: true
            },
            computed: {
                info() {
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                changeWeather() {
                    this.isHot = !this.isHot
                }
            },
            watch: {
                // 监视谁我们就写谁的名字
                isHot: {
                    // 初始化时让handler函数调用一下
                    immediate: true,

                    // 此函数什么时候被调用?当我们被监视的isHot改变时
                    // 此函数有两个参数,一个参数是新值,另一个参数是老值(之前的值
                    handler(newValue, oldValue) {
                        console.log('isHot被修改了')
                    }
                }
            }
        })

    </script>

这个地方监视属性应该是如下所示,上面所写的是简写形式,将双引号去除掉了

'isHot': {
                    // 初始化时让handler函数调用一下
                    immediate: true,

                    // 此函数什么时候被调用?当我们被监视的isHot改变时
                    // 此函数有两个参数,一个参数是新值,另一个参数是老值(之前的值
                    handler(newValue, oldValue) {
                        console.log('isHot被修改了')
                    }
                }

2.1.2 写法② vm.$watch

通过vm实例实现监视vm.$watch

 <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
           const vm = new Vue({
                el:'#root',
                data:{
                    isHot:true
                },
            computed:{
                info(){
                    return this.isHot ? '炎热':'凉爽'
                }
            },
            methods: {
                changeWeather(){
                    this.isHot = !this.isHot
                }
            },
 
            vm.$watch('isHot',{
               immediate: true,
                 handler(newValue,oldValue){
                 console.log('isHot被修改了')
                  }
            })
 
        })
 
        </script>  

2.2 深度监视

Vue自身可以检测对象内部值的改变,但Vue提供的watch默认不可以!

使用watch时根据数据的具体结构,是否采用深度监视

深度监视

Vue中的watch默认不监测对象内部值的改变(一层)

配置deep:true可以检测对象内部值改变(多层)

2.2.1 监视多级结构中某个属性的变化

监视number中的a的变化

            data:{
                isHot:true,
                numbers:{
                    a:1,
                    b:1
                }
            },

为什么这个地方会有引号?没有行不行?

不行!因为这才是正统的写法,没有引号的那种是简写形式

            'numbers.a':{
                // 如果没有这个函数的话会被警告
               handler(){
                console.log('a被改变了!')
               }
            }

2.2.2 监视多级结构中所有属性的变化(深度监视)

开启深度监视,当number中的任何一个配置变了之后,就会运行handler函数

deep:true

        watch:{
            isHot:{
                immediate:true,  //初始化时让handler调用一下
                // handler什么时候调用?当isHot发生变化时
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue)
                }
            },
 
            numbers:{
                // 开启深度监视,当number中的任何一个配置变了之后,就会运行handler函数
                deep:true,
                handler(){
                    console.log('numbers changes')
                }
            }
        }

2.3 监视属性简写

  •     完整版
            watch:{
                'isHot':{
                    immediate:true,  //初始化时让handler调用一下
                    deep:true, //开启深度监视
                    // handler什么时候调用?当isHot发生变化时
                    handler(newValue,oldValue){
                        console.log('isHot被修改了',newValue,oldValue)
                    }
                }
            }
            vm.$watch('isHot',{
                 immediate: true,
                 deep:true,
                 handler(newValue,oldValue){
                 console.log('isHot被修改了')
                  }
            })

  • 简写版

不允许写成箭头函数,Vue实例所管理的函数都不要写成箭头函数

简写的代价就是不能配置immediate和deep

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

2.4 姓名案例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
           <!-- 容器 -->
           姓:<input type="text" v-model="firstName"><br/><br/>
           名:<input type="text" v-model="lastName"><br/><br/>
           全名:<span> {{fullName}}</span>
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
          const vm  =  new Vue({
                el:'#root',
                data:{
                    firstName:'张',
                    lastName:'三',
                    fullName:'张-三'
                },
                watch:{
                    firstName:{
                        // 此处的newValue就是我们新输入的姓
                        handler(newValue,oldValue){
                        this.fullName=newValue+'-'+this.lastName
                        }
                    },
                    lastName:{
                        // 此处的newValue就是我们新输入的名
                        handler(newValue,oldValue){
                        this.fullName=this.firstName+'-'+newValue
                        }
                    }
                }
            })
 
        </script>   
    </body>
</html>

三、computed与watch对比

区别

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

  • watch能完成的功能,computed不一定能完成,例如watch可以进行异步操作

比如下图中我们在监视firstName时,加了一个定时器setTimeout

定时器的函数是一个箭头函数,此箭头函数不是Vue所管理的函数,定时器到点了是JS引擎帮我们调用的,里面的“this”指的是Vue实例

为什么不是Vue所管理的函数,“this”指代的还是Vue实例呢?

因为箭头函数没有自己的“this”,会向外找,看自己的上一级firstName,发现是Vue实例

watch:{
    firstName:{
         // 此处的newValue就是我们新输入的姓
         handler(newValue,oldValue){
             setTimeout(())=>{
                this.fullName=newValue+'-'+this.lastName
             },1000);
         },
    lastName:{
         // 此处的newValue就是我们新输入的名
         handler(newValue,oldValue){
           this.fullName=this.firstName+'-'+newValue
         }
    }
}

如果我们把定时器的函数写成普通函数,JS调用定时器时里面的“this”指的是Windows实例

setTimeout(function(){
  this.fullName=newValue+'-'+this.lastName
 },1000);

image-20231031093448963

重要原则

1. 所被Vue管理的函数,最好写成普通函数,这样"this"的指向才是vm或组件实例对象

2. 所有不被vue所管理的函数(定时器的回调函数、AJAX的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱布朗熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值