什么是vue的监视属性?
监视就是对内置对象的状态或者属性变化进行监听并且做出反应的响应,在 Vue.js 中,监视属性(watchers)是用于观察 Vue 实例中的数据变动的一种机制,当需要在数据变化时执行异步或开销较大的操作时,适合使用监听属性。
监视属性的使用
监视属性watch:
1.当被监视的属性变化时, 回调函数自动调用, 进行相关的操作。
2.监视的属性必须存在,才能进行监视!
3.监视的两种写法:
- new Vue时传入watch配置
- 通过vm.$watch监视
4.immediate配置项置为,初始化时让handler调用一下
如下所示为监视输入框变化的一个样例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="weather" placeholder="请输入天气">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
Vue.config.devtools = true
const vm = new Vue({
el: '#app',
data: {
weather: '晴天',
},
//1.new Vue时传入watch配置
watch: {
weather:{
immediate:true,
handler(newValue,oldValue){ //newValue是新值,oldValue是旧值
console.log('监视到天气被修改了')
console.log(newValue,oldValue)
}
}
}
})
//2.通过vm.$watch监视
/* vm.$watch('isHot',{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当weather发生改变时。
handler(newValue,oldValue){
console.log('weather被修改了',newValue,oldValue)
}
})*/
</script>
</html>
控制台上可以看出,输入框中的值发生变化被监视并在控制台输出变化前后的值。
当immediate 设置为 true 初始时以触发当前handler回调,此时没有旧值,所以第二个参数返回值为undefined。
深度监视
当我们的对象有多层结构的时候,我们要监听的对象的属性很多,避免一个一个属性单独写,这个时候用到监视中的一个配置项叫做深度监听。
在watch配置中,监视属性对象中,配置deep 设置为 true 用于监听多级对象或者数组内部值的变化
(1).Vue中的watch默认不监测对象内部值的改变(一层)。
(2).配置deep:true可以监测对象内部值改变(多层)。
注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
(3).深度监听时会出现新旧值相同的现象.(在变异(不是替换)对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue不会保留变异之前值的副本 )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="weather" placeholder="请输入天气">
<input type="text" v-model="hobbys.hobby1" placeholder="请输入爱好">
<input type="text" v-model="hobbys.hobby2" placeholder="请输入爱好">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
Vue.config.devtools = true
const vm = new Vue({
el: '#app',
data: {
weather: '晴天',
hobbys: {
hobby1: '读书',
hobby2: '看报'
}
},
watch: {
weather: {
immediate: true,
handler(newValue, oldValue) {
console.log('监视到天气被修改了')
console.log(newValue, oldValue)
}
},
//监视多级结构某个属性的变化
//Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
//如果这里只给外层hobbys设置监视属性,hobby1和hobby2改变时不奏效
/* 'hobbys.hobby1': {
handler(newValue, oldValue) {
console.log('hobby1被改变了')
}
},
'hobbys.hobby2': {
handler(newValue, oldValue) {
console.log('hobby2被改变了')
}
},
*/
//开启配置项中的深度监视,可以监视到里层对象值属性的变化,不管里面多少层都可以监视到
hobbys:{
deep:true,
handler(newValue, oldValue) {
console.log('hobbys被改变了')
}
}
}
})
</script>
</html>
两个输入框中的任何一个的值发生变化,都会触发监视属性。
监视属性的简写
正常写法
//new Vue引入的 正常写法
watch: {
weather: {
// immediate: true,
// deep:true,
handler(newValue, oldValue) {
console.log('监视到天气被修改了')
console.log(newValue, oldValue)
}
},
}
//vm.$watch的正常写法
//正常写法
vm.$watch('weather',{
immediate:true, //初始化时让handler调用一下
deep:true,//深度监视
handler(newValue,oldValue){
console.log('监视到天气被修改了',newValue,oldValue)
}
})
简写写法
//new Vue引入的watch简写
watch:{
weather(newValue,oldValue){
console.log('监视到天气被修改了')
}
}
//vm.$watch的简写
vm.$watch('weather',(newValue,oldValue)=>{
console.log('i监视到天气被修改了',newValue,oldValue,this)
})
计算属性与监视属性的区别
计算属性是依赖的值改变后重新计算结果更新DOM,会进行缓存。
属性监听的是属性值,当定义的值发生变化时,执行相对应的函数。
最主要的用途区别: 计算属性不能执行异步任务。计算属性一般不会用来向服务器请求或者执行异步任务,因为耗时可能会比较长,我们的计算属性要实时更新。所以这个异步任务就可以用监听属性来做。
总而言之:computed能实现的,watch都能实现,computed不能实现的,watch也能实现
下面是一个用监视属性实现姓名案例的例子(有许多注意事项)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>demo</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调
函数),最好写成箭头函数,
这样this的指向才是vm 或 组件实例对象。
-->
<!-- 准备好一个容器-->
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
firstName:'小',
lastName:'明',
fullName:'小-明'
},
//此处用计算属性不奏效,实现不了指定效果,因为此处return将结果返回给定时器而非fullName
/* computed:{
fullName(){
console.log('get被调用了')
setTimeout(()=>{
return this.firstName+'-'+this.lastName
})
}
}*/
watch:{
firstName(val){ //此处只需要变化后的新值,所以只需要传入一个参数val,代表变化后的新值
setTimeout(()=>{ //此处用的是箭头函数,箭头函数没有自己的this指向,沿用上级的this指向,所以是vue实例对象,此处如果用普通函数,this的指向就不是vue实例
console.log(this)
this.fullName = val + '-' + this.lastName
},1000);
},
lastName(val){
this.fullName = this.firstName + '-' + val
}
}
})
</script>
</html>