watch监听属性
在Vue中,也存在着这个重要的监听属性,同样也是监听Vue实例中数据的变化。先上代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>江河三千里</title>
<script type="text/javascript" src="http://ljy0427.online/js/vue.js"></script>
<style>
div {
margin-top: 10px;
}
</style>
</head>
<body>
<div id="app">
<h2>苹果</h2>
<div>数量:<input v-model="num"></div>
<div>价格:<input v-model="price.toFixed(2)"></div>
<div>总价:{{totalPrices}}</div>
<div>我有:<input v-model="OwnPrice" @keyup.enter="buy"></div>
<div>可以买:{{buyNum}}个</div>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
var vm = new Vue({
el: '#app',
data: {
num: 2,
price: 2.00,
OwnPrice: 0,
buyNum: 0,
totalPrices:0
},
watch:{
num:{
handler(newValue,oldValue){
console.log([newValue,oldValue]);
}
}
},
methods: {
buy() {
this.totalPrices = this.OwnPrice
console.log("购买");
}
}
});
</script>
</html>
通过以上代码,可以发现,watch和computed有点类似,但要记住一点,computed能够完成的事情,watch也能完成,并且,computed不能完成的某些需求,watch也能完成。
首先看watch怎样写
1.具体代码
watch:{
num:{
handler(newValue,oldValue){
console.log([newValue,oldValue]);
}
}
}
首先可以看出最大的区别,就是watch的监听属性,必须要先在data中声明,而且还有个最大的特点,就是watch同时还可以监听computed中的计算属性。
并且最大的区别就是,这里通过这种对象的方式定义监听属性的时候,使用的handler函数,并不是想computed那样是通过set,get方式,这里就可以看出,其两者的底层实现原理不同了。
并且这和hadnler函数,会接收两个参数值,第一个参数就是当前监听属性改变值的新值,第二个参数就是当前监听这个属性在发生改变之前的值。
同时还可以联想到,既然是通过这种方式定义的监听属性,那么就应该还存在着其他的配置属性,确实存在的,只不过这里只简单介绍两个配置属性immediate和deep
immediate
immediate译为立即,在wathc中的作用也是这样,就是让当前监听属性的时间立即执行,其默认值为false。
num:{
immediate:true,
handler(newValue,oldValue){
console.log([newValue,oldValue]);
}
}
这里就可以看出来将该属性设置为true之后,当Vue实例渲染完成之后,就会立即执行该handlr函数,并且会发现,oldValue为undefined,这里我的理解是,在Vue实例构建的时候,只是构建了这个num变量,就相当于var num;这种时候num的值就为undefined了,然后渲染结束之后,再为其赋值,所以newValue是就是自己在data中所定义的值了。
deep
deep译为深度,在watch中的作用是深度监听
<body>
<div id="app">
<div>
水果名称:{{fruit.name}}
</div>
<div>
水果价格:{{fruit.price}}
</div>
<div><input type="text" v-model="changeName" placeholder="输入修改名称"> <button @click="CN">点击修改水果名称</button></div>
<div><input type="text" v-model="changePirce" placeholder="输入修改价格"> <button @click="CP">点击修改水果价格</button></div>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
var vm = new Vue({
el: '#app',
data: {
fruit: {
name: "苹果",
price: "2.00"
},
changePirce: "",
changeName: ""
},
watch: {
fruit: {
immediate: true,
handler(newValue, oldValue) {
console.log([newValue, oldValue]);
}
}
},
methods: {
CN() {
console.log(`名称发生了改变,值=${this.changeName}`);
this.fruit.name=this.changeName
},
CP() {
console.log(`价格发生了改变,值=${this.changePirce}`);
this.fruit.changePirce=this.changePirce
},
}
});
</script>
</html>
在上述代码中,改变了一下例子,将水果当成了一个对象,定义在了data中,这种时侯,看下效果
从这里就可以看出了,当水果名称改变时,watch监听属性不起作用了,其实这个就是由于没有开启watch的深度监听所导致的。
watch这样修改试试
watch: {
fruit: {
immediate: true,
handler(newValue, oldValue) {
console.log([newValue, oldValue]);
}
},
"fruit.name":{
handler(newValue, oldValue) {
console.log([newValue, oldValue]);
}
},
"fruit.price":{
handler(newValue, oldValue) {
console.log([newValue, oldValue]);
}
}
}
发现这种方式确实改变了,但是这种方式,有个弊端,很明显,也就是如果这个对象中有很多属性,那岂不是要写很多这种方法,代码的冗余程度就增加了,这种时候就需要deep这个配置对象了,其默认值为false,将其修改成true即可
fruit: {
immediate: true,
deep:true,
handler(newValue, oldValue) {
console.log([newValue, oldValue]);
}
}
效果如图,这种时候,当属性的值发生改变是,handler也触发了,但是如果按照之前说的handler所接收得到两个参数,第一个是新值,第二个是修改之前的值,但是这里却输出的都一样啊,这个我认为就验证了我的观点了,这里传入的是一个地址,没有对地址修改,所以以前的值都一样,修改的只是其中的某一个属性
watch简写
watch也有简写形式,当不考虑这些配置对象的时候,即immediate和deep等时,就可以采用简写形式
fruit(newValue, oldValue){
console.log([newValue, oldValue]);
}