Vue核心⑤(监视属性)

举报
十八岁讨厌编程 发表于 2022/08/05 23:05:13 2022/08/05
【摘要】 文章目录 案例引入监视属性深度监视监视的简写形式watch对比computed 案例引入 我们实现以下的一个小案例: 点击切换天气会分别显示凉爽、炎热(只有这两种状态),且每一次天气切换...

案例引入

我们实现以下的一个小案例:
在这里插入图片描述
点击切换天气会分别显示凉爽、炎热(只有这两种状态),且每一次天气切换的时候都会被控制台给捕获到。

我们先不考虑控制台的那一部分,先把切换部分给做出来。

我们可以使用前文刚刚介绍的计算属性。第一部分实现代码如下:

	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
			},
			computed:{
				info(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot
				}
			},
		})
	</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

此处有两个注意点:
①如果我们把上述代码模板中的插值语法给去掉,也就是这样:
在这里插入图片描述
因为此时已有属性、计算属性在模板当中都没有使用,故会导致Vue的开发者工具出现一点小问题。
我们发现,点击了切换按钮之后,开发者面板中的属性值并没有发生变化:
在这里插入图片描述
事实是:数据已经更新了,但是开发者面板中没有更新,我们可以验证一下:
在这里插入图片描述
②一个小技巧
@click后面可以写一些简单的语句(就是你回调函数里面的语句),例如上面的代码我们还可以这样写:
在这里插入图片描述
同样也可以进行多项操作(理论上回调函数里面所有的语句都可以写在里面):
在这里插入图片描述
效果:
在这里插入图片描述
不过这么写容易乱套,建议逻辑简单的时候可以使用这种技巧,如果复杂还是中规中矩的写回调函数。
同时这个方法还有一个注意点:不是所有的语句都可以执行的。例如:
在这里插入图片描述
报错:
在这里插入图片描述
因为alert是window身上的方法,而模板之中把对象给写死了就是vm,不会说找不到再去外头一层找(但会再去vm的原型对象上继续找,当然肯定是找不到的)。故这里alert是不能用的。
当然这种情况你非要解决也是有办法的(可以但没必要),就是让window可见就行:
在这里插入图片描述
我们直接将window放在data中,这样在模板中就可见了。

然后控制台的捕获部分就要使用监视属性了。

监视属性

监视属性顾名思义就是我们要监视的属性。那么我们如何去监视一个属性呢。Vue为我们提供了一个新的配置项watch。我们直接看相关实现代码,再进行解释:

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

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		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调用一下
					//handler什么时候调用?当isHot发生改变时。
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}
			} 
		})
	</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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

watch里面的被监视属性同样也要写成一个配置对象。其中:

  • handler是一个回调函数,当被监视的属性值发生变化的时候就会被调用。它会被传入两个参数:一个新值,一个旧值。
  • immediate是一个布尔属性,默认值是false。当设置为true的时候表示初始化的时候也要调用以下handler

不论是已有的属性还是计算属性都可以被监视

我们也可以不通过watch来进行监视,我们可以直接通过vm实现监视(前提是确保vm实例对象已经被创建完毕),代码如下:

	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		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调用一下
					//handler什么时候调用?当isHot发生改变时。
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}
			} */
		})

		vm.$watch('isHot',{
			immediate:true, //初始化时让handler调用一下
			//handler什么时候调用?当isHot发生改变时。
			handler(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue)
			}
		})
	</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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

注意:$watch()这个方法的第一个参数是要监视的对象。这个地方是有引号的。我们对象中的属性不写引号是一种简写形式,如果写全的话也是有引号的(因为是字符串类型)。

那么这两种我们如何选择呢?
如果一开始,也就是创建vm实例对象的时候,就已经很明确要监视谁,就可以直接选择watch配置,
如果创建实例的时候不是很明确要检测谁,后续根据用户的行为才能确定。那么就可以选择vm的相应api来监视

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

深度监视

我们还是通过一个案例来理解:我们想检测number中的a的变化(b如果发生变化不管)
在这里插入图片描述
网页端:
在这里插入图片描述
也就是说监视多级结构中某个属性的变化,代码实现如下:

在这里插入图片描述
之所以加引号是因为对象里的key必须是字符串,里面直接写.是不可以的,所以我们只能还原原始的写法。

实现效果:
在这里插入图片描述

现在我们有新的需求,我们想要检测numbers中所有属性的变化(也就是说只要其中一种属性发生了变化就会被监测到),如果numbers中有很多很多的属性,继续沿用上面的代码的思路显然代码会非常冗长麻烦。这个时候我们就可以使用深度监视

我们只需要添加一个配置项deep即可。它的默认值是false,以此来保证程序的运行效率。

监视多级结构中所有属性的变化,代码如下:

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

	</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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

小结:
深度监视:
(1).Vue中的watch默认不监测对象内部值的改变(一层)。
(2).配置deep:true可以监测对象内部值改变(多层)。
备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。

监视的简写形式

使用前提:当你监视属性的配置项中只有handler的时候才可以使用。

与前文的计算属性的简写方法一致,直接写成一个函数。函数名对应监视的函数名,方法体就是handler的方法体。

代码如下:

	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		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调用一下
					// deep:true,//深度监视
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}, */
				//简写
				/* isHot(newValue,oldValue){
					console.log('isHot被修改了',newValue,oldValue,this)
				} */
			}
		})
	</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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

同样的我们也可以使用vm的api进行监视,常规及简写版如下:

		//正常写法
		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)
		})

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

注意:此处不能写箭头函数(Vue管理的函数不能写成箭头函数)

watch对比computed

我们发现有时候一个功能可以用这两种方式分别实现。例如我们还是使用前面的一个小案例:有3个input框,姓、名、姓名。当姓和名发生变化的时候,姓名会跟着动态的发生变化。

watch实现:

<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:'三',
            fullName:'张-三'
        },
        watch:{
            firstName(newValue){
                this.fullName = newValue + '-' + this.lastName
            },
            lastName(newValue){
                this.fullName = this.firstName + '-' + newValue
            },
        }

    })
</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

computed实现:
在这里插入图片描述
从这里可以看出使用计算属性的代码是比监听属性更加简洁的。但是这并不是绝对的,有时候我们要实现的功能甚至只有监听属性才能做。

下面我们讲将案例进行修改:我们要求修改之后的变化延迟一秒才生效。

代码实现如下:
使用监视属性实现:

<script>
    const vm = new Vue({
        el:"#root", 
        data:{
            firstName:'张',
            lastName:'三',
            fullName:'张-三'
        },
        watch:{
            firstName(newValue){
                setTimeout(() => {
                    this.fullName = newValue + '-' + this.lastName
                }, 1000);
            },
            lastName(newValue){
                setTimeout(() => {
                    this.fullName = this.firstName + '-' + newValue
                }, 1000);
            },
        }

    })
</script>

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

使用计算属性是不能完成这个需求的。因为计算属性的变化全靠return,而我们是没有办法实现延迟return的。

如果你用setTimeout函数将return包裹,那么return里的东西返回给了延时函数,而不是计算属性的那个函数,相当于外层函数没有返回值,那么相应的计算属性也不会发生变化
在这里插入图片描述

所以我们可以知道:
计算属性里面是不能开启异步任务去维护数据的。但是使用监视属性是可以完成的。

当有一个需求,watch能实现computed也能实现,我们一般使用计算属性。但是当我们面临一些异步的计算的时候,我们就要使用watch.

同时还有一个小问题:
在这里插入图片描述
我们在这个箭头函数里面使用了this,那么它指向的是Vue的实例对象吗?

确实如此。我们可以在此基础上进行总结:

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

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

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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