Vue核心④(计算属性)

举报
十八岁讨厌编程 发表于 2022/08/05 22:48:02 2022/08/05
【摘要】 文章目录 案例引入计算属性简写形式 案例引入 现在我们做一个小案例,如下图所示: 我们创建三个input框,其中第一个框写姓,第二个框写名,第三个框是姓名,也就是将第一个框中的内容和第二...

案例引入

现在我们做一个小案例,如下图所示:
在这里插入图片描述
我们创建三个input框,其中第一个框写姓,第二个框写名,第三个框是姓名,也就是将第一个框中的内容和第二个框中的内容中间用-连接在一起。同时在修改姓、名的时候姓名会跟着动态的发生变化。

这个需求很简单,代码实现如下:

<body>
    <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="firstName + '-' + lastName">
    </div>
    
</body>
<script>
    new Vue({
        el:"#root",
        data:{
            firstName:'张',
            lastName:'三'
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

现在我们提一个新需求:不管姓、名有多长,我们永远只截取他们的前三位进行拼接。我们可以用多种方法去实现它:

方法①:直接调用api
首先我们的第一反应是直接调用相关的api
代码实现如下:

<body>
    <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="firstName.slice(0,3) + '-' + lastName.slice(0,3)">
    </div>
    
</body>
<script>
    new Vue({
        el:"#root",
        data:{
            firstName:'张',
            lastName:'三'
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

但是考虑到如果需求变得更加复杂,如果将处理逻辑全写在那个地方,会造成语义不清让人难以理解的情况,我们将处理逻辑抽象出来,放在methods里面。

方法②:将处理逻辑放入到methods中

原理:methods中的方法会原封不动的被复制一份到Vue的实例对象中,于是我们就可以在模板中去使用它。

<body>
    <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="minNum()">
    </div>
    
</body>
<script>
    new Vue({
        el:"#root", 
        data:{
            firstName:'张',
            lastName:'三'
        },
        methods:{
            minNum(){
                return this.firstName.slice(0,3) + '-' + this.lastName.slice(0,3)
            }
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

注意:
①想要在minNum方法里面访问到firstName,lastName两个属性我们有两种方法。一种是变量提升,另一种就是借用方法的调用者Vue的实例来进行访问(因为firstName,lastName这两个属性都会在Vue的实例中进行代理,故可以直接使用)
②在事件绑定中,那个回调函数我们可以加括号也可以不加括号(因为Vue会自动帮你执行)。但是在这个地方我们都要加上括号。
当data中的任何一个数据发生变化的时候,Vue的模板都会重新解析一遍,因此你模板里面的调用函数也会重新执行一遍,以此来达到数据更新的效果。我们可以试验一下:
我们整体代码不变,将minNum方法进行一个小的修改:
在这里插入图片描述
然后我们一次往姓中添加1,2,控制台结果如下:
在这里插入图片描述

但是如上的方法是有一些小问题的,并且他的效率并不高,所以我们使用第三种方法。

方法③:计算属性

那么怎么去写呢?我们要先来知道它是什么

计算属性

计算属性就是使用已有的属性经过加工与计算得到一个全新的属性

在Vue中属性与计算属性是分开放的,data中的放的都是属性,而计算属性放在配置项computed中,其值也写成一个对象的形式。同时computed中的属性其对应的值也要配置成一个对象,其中有getter和setter(setter并不是必须的,如果你确定这个属性只会被读取不会被修改那么可以不配置setter)。

getter函数的作用与我们前文所涉及的一样:当有人读取计算属性时,get就会被调用,且返回值就作为相应计算属性的值

同理setter:当有人修改计算属性时,set就会被调用,且返回值就作为修改的计算属性的值。

原理:底层借助了Objcet.defineproperty方法提供的getter和setter。

放在computed里面的计算属性,他并未使用代理,而是直接将已有属性进行处理之后放到了Vue实例对象的身上.

vm实例对象上有一个属性时_data,这个属性里面不会出现计算属性。也就是说_data里面的属性是已有属性。

这里有一个注意点:
例如在写getter时候,我们如何去拿到data中的数据呢?我们的思路肯定是借助Vue的实例对象去拿到相应的值。幸运的是Vue已经提前帮我们维护好了get函数里面的this指向,将其设为了vm(也就是Vue的实例对象)。

接下来我们使用计算属性的办法,来实现前面的案例:

<body>
    <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="fullName">
    </div>
    
</body>
<script>
    new Vue({
        el:"#root", 
        data:{
            firstName:'张',
            lastName:'三'
        },
       computed:{
           fullName:{
            get(){
               return this.firstName.slice(0,3) + '-' + this.lastName.slice(0,3)
            }
           }
           
       }
    })
</script>

  
 
  • 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

那么这个使用计算属性的方法他好在哪里?我们可以看看下面的代码:

<body>
    <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="fullName">
        姓名:<input type="text" :value="fullName">
        姓名:<input type="text" :value="fullName">
        姓名:<input type="text" :value="fullName">
    </div>
    
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

按照getter的特点,我们会觉得它会被调用四次,但是事实上并不是这样,getter仍只会被调用一次,因为他有着一种独特的缓存机制。也就是说上面的第一个fullName是经历了标准的步骤拿到get的返回值并将其作为fullName的值进行使用,并将结果进行缓存。而进行到后面几个fullName的时候,他并没有找getter要,而是直接走的缓存路线。

那么有一个问题衍生而来:如果数据被修改,那么以后还是读取缓存的值怎么办?

所以这里get的调用是由两个时机的

  • 初次读取计算属性的时候
  • 计算属性所依赖的数据发生变化时

然后我们再引入setter:

它在计算属性被修改的时候调用。他有一个形参,可以接收修改的值。

<body>
    <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="fullName">
    </div>
    
</body>
<script>
    const vm = new Vue({
        el:"#root", 
        data:{
            firstName:'张',
            lastName:'三'
        },
       computed:{
           fullName:{
            get(){
               return this.firstName.slice(0,3) + '-' + this.lastName.slice(0,3)
            },
            set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
			}
           }  
       }
    })
</script>

  
 
  • 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

set里面不要去直接修改fullName,否则它会在set方法中再去调用set,从而产生无限递归,造成栈溢出。因为fullName是通过firstName与lastName的计算得来的,所以我们应该对他的两个依赖数据进行修改。

注意:getter和setter不要用箭头函数去写,否则this会由Vue的实例对象变成window

总结:
在这里插入图片描述

注意:
定义中一定是已有的属性,而不是已有的数据、变量······,否则它极有可能脱离Vue的管理,无法监测到它的变化。

简写形式

在不适用setter的前提下我们可以直接将计算属性写成一个函数

简写形式如下:

	<body>
      <div id="root">
        姓:<input type="text" v-model:value="firstName"> <br>
        名:<input type="text" v-model:value="lastName"> <br>
        姓名:<input type="text" :value="fullName">
      </div>
	</body>

	<script type="text/javascript">
		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
			},
			computed:{
				//简写
				fullName(){
					return this.firstName + '-' + this.lastName
				}
			}
		})
	</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

与完整的写法相比简洁了许多

文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/zyb18507175502/article/details/125121564

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。