20.Vue侦听器:watch

简介

watch可以监控一个值的变换,并调用因为变化需要执行的方法。可以通过watch动态改变关联的状态。

data:{
     a:1,
     b:{
         c:1
     }
 },
 watch:{
     a(val, oldVal){ //普通的watch监听
         console.log("a: "+val, oldVal);
     },
     b:{ //深度监听,可监听到对象、数组的变化
         handler(val, oldVal){
             console.log("b.c: "+val.c, oldVal.c);
         },
         deep:true //true 深度监听
     }
 }

 

侦听属性

现在我们侦听属性num的变化,当它变化时要打印出变化。

	<body>
		<div id="content">
			<button type="button" @click="add">+1</button>
			<div>
				{{num}}
			</div>
		</div>
	</body>
	<script>
		var vm = new Vue({
			el: '#content',
			data: {
				num: 0
			},
			methods:{
				add(){
					this.num++;
				}
			},
			watch:{
				num:function(newValue,oldValue){
					console.log(`num改变了,改变前:${oldValue},改变后:${newValue}`);
				}
			}
		});
	</script>

运行:
在这里插入图片描述
 

侦听数组

由于js的限制,vue中数组更新数据在有些情况下并不会渲染。

不会更新渲染的情况:

  • 利用索引直接设置一个项时,例如:arr[0] = newValue
  • 修改数组的长度时,例如:arr.length = newLength

会更新渲染的情况:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()
  • vue2.0还增加了Vue.set(items, indexOfItem, newValue)
  • filter(), concat(), slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组

实例:

	<body>
		<div id="content">
			<button type="button" @click="add">+1</button>
			<button type="button" @click="remove">pop</button>
			<div>
				{{arr}}
			</div>
		</div>
	</body>
	<script>
		var vm = new Vue({
			el: '#content',
			data: {
				arr: [0, 2, 3, 4, 7, 9, 6, 45, 3],
			},
			methods: {
                 //数组第一个元素++
				add() {
					this.arr[0]+=1;
				},
                //移除数组最后一个元素
				remove() {
					this.arr.pop()
				}
			},
			watch: {
				arr:function(newValue,oldValue){
					console.log(`num改变了,改变前:${oldValue},改变后:${newValue}`);
				}
			}
		});
	</script>

运行add()更新了数据,但没有渲染,没有被侦听到。remove()更新了数据,有渲染,有被侦听到。
在这里插入图片描述
解决方法,数组的splice(index,howmany,newItem1,…,newItemX)或者Vue.set(items, indexOfItem, newValue):

	<body>
		<div id="content">
			<button type="button" @click="add">+1</button>
			<button type="button" @click="remove">pop</button>
			<div>
				{{arr}}
			</div>
		</div>
	</body>
	<script>
		var vm = new Vue({
			el: '#content',
			data: {
				arr: [0, 2, 3, 4, 7, 9, 6, 45, 3],
			},
			methods: {
				add() {  
					let temp = this.arr[0] + 1;
                    //使用数组的splice方法
					this.arr.splice(0, 1, temp);
                    //使用Vue.set也行
                    //this.$set(this.arr, 0, temp);
				},
				remove() {
					this.arr.pop()
				}
			},
			watch: {
				arr: function(newValue, oldValue) {
					console.log(`num改变了,改变前:${oldValue},改变后:${newValue}`);
				}
			}
		});
	</script>

运行,虽然达到了我们想要的效果,但是log中,监听到的newValue和oldValue相同。这是因为在变异 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变异之前值的副本
在这里插入图片描述
要解决这个问题,需要深拷贝再替换旧数组。

add() {
	let brr = [];
	for (var item in this.arr) brr[item] = this.arr[item]; //循环遍历赋值来深拷贝
	brr[0]++; //操作新数组
	this.arr = brr; //新数组替换旧数组
},

运行,newValue和oldValue是预期的样子了:
在这里插入图片描述
 

侦听对象

现在有一个对象obj,三个按钮分别可以让obj名字改变,年龄增加,增加一个sex属性并赋值。

	<body>
		<div id="content">
			<button type="button" @click="changeName">改变名字</button>
			<button type="button" @click="addAge">增加1岁</button>
			<button type="button" @click="addSex">增加性别属性</button>
			<div>
				{{obj}}
			</div>
		</div>
	</body>
	<script>
		var vm = new Vue({
			el: '#content',
			data: {
				obj: {
					"name": "张三",
					"age": 18
				}
			},
			methods: {
				changeName() {
					this.obj.name = this.obj.name + "增加";
				},
				addAge() {
					this.obj.age++;
				},
				addSex() {
					this.obj.sex = "男";
				}
			},
			watch: {
				obj: function(newValue, oldValue) {
					console.log(`obj改变了,改变前:${oldValue},改变后:${newValue}`);
				}
			}
		});
	</script>

运行发现,改变name和age时数据和视图更新了,侦听无反应。增加sex属性时,数据更新了,侦听无反应。
在这里插入图片描述
这个问题可以通过**深度侦听(deep:true)**解决。

watch: {
    obj: {
    	handler(newValue, oldValue) {
    		console.log("obj改变了!")
    		console.log("旧的obj:")
    		for (const value in oldValue) {
    			console.log(value + ":" + oldValue[value]);
    		}
    		console.log("新的obj:")
    		for (const value in newValue) {
    			console.log(value + ":" + newValue[value]);
    		}
    	},
    	deep: true //深度侦听
   }
}

运行,name和age确实达到了预期的更新,不过log中oldValue与newValue相同。而且新增sex属性没有被监听到,sex渲染更新也不及时。
在这里插入图片描述
oldValue与newValue相同的问题如同上面数组一样,使用深拷贝可以解决,不再赘述。要解决sex渲染更新的问题可以使用Vue.set(obj, props, newValue):

addSex() {
	// this.obj.sex = "男"; //无效
	this.$set(this.obj, 'sex', '男')
}

运行:
在这里插入图片描述
 

相关资料

vue深入响应式原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值