数据改变(vue视图上的数据能渲染成功)时会触发对应的监听器watch。
vue提供了watch
方法,用于监听实例内data
数据的变化。
一、普通类型字符串等监听
直接监听
<template>
<div class="about">
<!-- v-bind只视图绑定数据,视图修改无法触发监听watch方法,只能数据修改触发watch并渲染视图 -->
<!-- v-model实现双向数据绑定,视图修改触发监听watch方法 -->
<div>
<input type="text" :value="name" />
<button @click="change1">更新视图</button>
</div>
<div>
<input type="text" v-model="age" />
<button @click="change2">更新视图</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
name: "lilu",
age: 20,
};
},
methods: {
change1() {
this.name = this.name + "1";
},
change2() {
this.age = this.age + "1";
},
},
watch: {
// 修改字符串、数组直接渲染视图,监听到改变
name(newVal, oldVal) {
console.log("name:newVal--" + newVal + ",oldVal--" + oldVal);
},
age: function (newVal, oldVal) {
console.log("age:newVal--" + newVal + ",oldVal--" + oldVal);
},
}
}
</script>
二、对于对象
<template>
<div class="about">
<input type="text" :value="JSON.stringify(friend)" style="width: 300px" />
<input type="text" :value="friend.friendName" />
<button @click="changeFriendName">更新视图</button>
</div>
</template>
<script>
export default {
data() {
return {
obj: "oo",
friend: {
friendName: "yin",
age: 24,
},
};
},
}
</script>
监听对象本身
直接监听对象是监听对象的指向,不能监听到某个对象里面属性的变化。
如果需要监听的数据是对象内的某一属性值的变化,直接watch
对象friend是检测不到变化的,这是因为friend这个对象的指向并没有发生改变。
<script>
export default {
watch: {
friend(newVal, oldVal) {
console.log("friend:newVal--" + newVal + ",oldVal--" + oldVal);
}
}
}
</script>
触发监听
直接改变对象会触发监听
this.friend = {
friendName: "yin",
name: "lu",
};
监听对象内属性变化
方法一:深度检测
deep
设为了true
,修改了这个friend中的任何一个属性,都会执行handler这个方法。不过这样会造成更多的性能开销,尤其是对象里面属性过多,结构嵌套过深的时候。而且有时候我们就只想关心这个对象中的某个特定属性。
<script>
export default {
watch: {
friend: {
handler(newVal, oldVal) {
console.log("deep friend:newVal--" + newVal + ",oldVal--" + oldVal);
},
deep: true,
},
}
}
</script>
扩展:handler声明函数或函数表达式都可以,但是不能箭头函数
watch : {
newA : {
handler : function (newVal, oldVal) {
console.log(newVal,oldVal)
},
immediate : true, //初始化页面后立即监听
deep: true,
}
}
immediate属性
没有的时候上面的例子是值变化时候,watch才执行,我们想让值最初时候watch就执行就用到了handler
和immediate
属性,immediate : true代表在wacth里声明了newA这个方法之后立即先去执行handler方法,如果设置了false,那么效果和没有一样
方法二:字符串来表示属性的调用
<script>
export default {
watch: {
"friend.friendName"(newVal, oldVal) {
console.log("string friend:newVal--" + newVal + ",oldVal--" + oldVal);
},
}
}
</script>
方法三:使用computed属性
<script>
export default {
watch: {
// 和computed计算属性名一样
friendName(newVal, oldVal) {
console.log("computed friend:newVal--" + newVal + ",oldVal--" + oldVal);
},
},
computed: {
friendName() {
return this.friend.friendName;
},
},
}
</script>
触发监听
1、修改现有对象某个属性对应的值
把对象某个属性的值修改都触发,无论改成基本类型还是引用对象,而且引用对象内vue也能监听到。
// 例1:数据修改成功,视图修改成功=三种方式的属性监听都触发
this.friend.friendName = "li";
2、属性的添加
对于已经创建的实例,Vue 不允许动态添加根级别(外层内层都监听不到)的响应式 property: 无法渲染
解决方案:
- 预先留出变量
- 使用this.$set / Vue.set()
this.friend.sex = "girl"; // 数据修改但无法渲染 = 监听不到
this.$set(this.friend, "sex", "boy"); // 可以渲染,deep watch可以监听
3、属性的删除
Vue 无法检测 property 的移除
解决方案:
- Vue.delete()删除对象某个元素后,会立即触发页面渲染:Vue.delete(propertyName/index)
delete this.friend.age; //数据删除但无法渲染 = 监听不到
this.$delete(this.friend, "age"); // 可以渲染,deep watch可以监听
三、对于数组
<template>
<div class="about">
<input type="text" :value="colors" />
<input type="text" :value="colors[0]" />
<button @click="changeColors">更新视图</button>
</div>
</template>
<script>
export default {
data() {
return {
colors: ["red", "orange", "green"]
};
},
}
</script>
监听数组
<script>
export default {
watch: {
colors(newVal, oldVal) {
console.log("colors:newVal--" + newVal + ",oldVal--" + oldVal);
},
},
}
</script>
触发监听
1、直接赋值新数组
// 例子1:修改成功,数组、元素都渲染成功,触发上面对数组的监听
this.colors = ["1", "2", "3"];
2、利用索引直接设置一个数组项
例如:arr[indexOfItem] = newValue;
解决方案:
- 使用this.$set(arr, index, newVal)
- 使用splice(indexOfItem, 1, newValue):
- 使用临时变量直接赋值的方式,原理与直接赋值数组一样
this.colors[0] = "blue"; // 不是响应的,数据修改成功但渲染不成功 = 不触发监听
// 方法一:
this.$set(this.colors, 0, "blue") // 渲染成功 = 触发监听
// 方法二
this.colors.splice(0, 1, "blue"); // 渲染成功 = 触发监听
// 方法三
let temp = [...this.colors];
temp[0] = "blue";
this.colors = temp; //渲染成功 = 触发监听
3、push数组
Vue可以监听
this.colors.push('yellow') // 数据添加成功,视图渲染成功
4、修改数组的长度
例如:arr.length = newLength
长度大于原数组就将后续元素设置为 undefined, 长度小于原数组就将多余元素截掉。
解决方案:
- this.$set(arr, index, newVal);
- 使用数组 splice 方法可以监听
- 使用临时变量直接赋值的方式,原理与直接赋值数组一样
this.colors.length = 1; // 数据修改成功,视图渲染不成功
方法一:
this.colors.splice(1) // 渲染成功 = 触发监听 1之后数组的元素都被删除,包括1