首页 > 编程笔记 > JavaScript笔记
Vue watch(监听器)用法详解
Vue 中的监听器是一个对象,以 key-value 的形式表示,key 是需要监听的表达式,value 是对应的回调函数,value 也可以是方法名,或者包含选项的对象。
Vue 实例将会在实例化时调用 $watch() 遍历 watch 对象的每一个 property。同时,当差值数据变化时,执行异步或开销较大的操作时,可以通过监听器的方式来达到目的。
监听器在 Vue 实例的 watch 选项中定义,它包括两个参数,第一个参数是监听数据的新值,第二个是旧值。
【实例一】监听 data() 函数中的 message 属性,并在控制台中打印新值和旧值。
图 1 监听属性值的变化
注意,不要用箭头函数来定义 watch 函数。例如:
【实例二】使用监听器方法。
在 Chrome 浏览器中运行程序,在第一个输入框中输入 6,可以发现第二个输入框的值相应地变为 60,如下图所示。
图 2 监听方法
同样,在第二个输入框中输入内容,第一个输入框也会相应地变化。
deep 属性在监听对象属性变化时使用,该选项的值为 true,表示无论该对象的属性在对象中的层级有多深,只要该属性的值发生变化,都会被监测到。
监听器函数在初始渲染时并不会被调用,只有在后续监听的属性发生变化时才会被调用;如果需要监听器函数在监听开始后立即执行,可以使用 immediate 选项将其值设置为 true。
【实例三】监听 goods 对象,在商品价格改变时显示是否可以采购。
图 3 输入“860”效果
从上面的示例可以发现,页面初始化时监听器不会被调用,只有在监听的属性发生变化时才会被调用;如果要让监听器函数在页面初始化时执行,可以使用 immediate 选项,将其值设置为 true。
图 4 immediate选项的作用
在上面的示例中,使用 deep 属性深入监听,监听器会一层一层地往下遍历,给对象的所有属性都加上这个监听器,修改对象里面任何一个属性都会触发监听器里的 handler 函数。
在实际开发过程中,用户很可能只需要监听对象中的某几个属性,设置 deep:true 之后就会增大程序性能的开销。这里可以直接监听想要监听的属性,例如修改上面的示例,只监听 score 属性。
【实例四】监听器对象的单个属性。
图 5 输入“北京”的效果
Vue 实例将会在实例化时调用 $watch() 遍历 watch 对象的每一个 property。同时,当差值数据变化时,执行异步或开销较大的操作时,可以通过监听器的方式来达到目的。
监听器在 Vue 实例的 watch 选项中定义,它包括两个参数,第一个参数是监听数据的新值,第二个是旧值。
【实例一】监听 data() 函数中的 message 属性,并在控制台中打印新值和旧值。
<div id="app"> 时:<input type="text" v-model="time"> 分钟:<input type="text" v-model="minute"> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ //该函数返回数据对象 data(){ return{ time:0, minute:0 } }, watch:{ time(val) { this.minute = val * 60; }, // 监听器函数也可以接收两个参数,val是当前值,oldVal是改变之前的值 minute(val, oldVal) { this.time = val / 60; } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,这里将分别监听数据属性 time 和 minute 的变化,当其中一个数据的值发生变化时,就会调用对应的监听器,经过计算得到另一个数据属性的值,结果如下图所示。
图 1 监听属性值的变化
注意,不要用箭头函数来定义 watch 函数。例如:
time:(val) =>{ this.time = val; this.minute = this.time*60 }因为箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.time 和 this.minute 都是 undefined。
监听方法
在使用监听器的时候,除了直接写一个监听处理函数外,还可以接收一个加字符串形式的方法名,方法在 methods 选项中定义。【实例二】使用监听器方法。
<div id="app"> <p>元和角的转换</p> <p>元:<input type="text" v-model="yuan"></p> <p>角:<input type="text" v-model="jiao"></p> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ //该函数返回数据对象 data(){ return{ yuan:0, jiao:0 } }, methods:{ method1:function (val,oldVal) { this.jiao=val*10; }, method2:function (val,oldVal) { this.yuan=val/10; } }, watch:{ //监听yuan属性,yuan变化时,使jiao属性等于yuan*10 yuan:"method1", //监听jiao属性,jiao变化时,使val属性等于jiao/10 jiao:"method2" } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>示例中监听了 yuan 和 jiao 属性,后面直接加上字符串形式的方法名 method1 和 method2,最后在页面中使用 v-model 指令绑定 yuan 和 jiao 属性。
在 Chrome 浏览器中运行程序,在第一个输入框中输入 6,可以发现第二个输入框的值相应地变为 60,如下图所示。
图 2 监听方法
同样,在第二个输入框中输入内容,第一个输入框也会相应地变化。
监听对象
当监听器监听一个对象时,使用 handler 定义数据变化时调用的监听器函数还可以设置 deep 和 immediate 属性。deep 属性在监听对象属性变化时使用,该选项的值为 true,表示无论该对象的属性在对象中的层级有多深,只要该属性的值发生变化,都会被监测到。
监听器函数在初始渲染时并不会被调用,只有在后续监听的属性发生变化时才会被调用;如果需要监听器函数在监听开始后立即执行,可以使用 immediate 选项将其值设置为 true。
【实例三】监听 goods 对象,在商品价格改变时显示是否可以采购。
<div id="app"> 商品价格:<input type="text" v-model="goods.price"> <p>{{pess}}</p> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ //该函数返回数据对象 data(){ return{ pess:'', goods: { name: '洗衣机', price:0 } } }, watch: { goods:{ //该回调函数在goods对象的属性改变时被调用 handler: function(newValue,oldValue){ if(newValue.price>=8000){ this.pess="价格太贵了,不可以采购!"; } else{ this.pess="价格合适,可以采购!"; } }, //设置为true,无论属性被嵌套多深,改变时都会调用handler函数 deep:true } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,在输入框中输入 860,下面会显示“价格合适,可以采购!”,如下图所示。
图 3 输入“860”效果
从上面的示例可以发现,页面初始化时监听器不会被调用,只有在监听的属性发生变化时才会被调用;如果要让监听器函数在页面初始化时执行,可以使用 immediate 选项,将其值设置为 true。
watch: { goods:{ //该回调函数在goods对象的属性改变时被调用 handler: function(newValue,oldValue){ if(newValue.price>=8000){ this.pess="价格太贵了,不可以采购!"; } else{ this.pess="价格合适,可以采购!"; } }, //设置为true,无论属性被嵌套多深,改变时都会调用handler函数 deep:true, //页面初始化时执行handler函数 immediate:true }此时在 Chrome 浏览器中运行程序,可以发现,虽然没有改变属性值,也调用了回调函数,显示了“价格合适,可以采购!”,如下图所示。
图 4 immediate选项的作用
在上面的示例中,使用 deep 属性深入监听,监听器会一层一层地往下遍历,给对象的所有属性都加上这个监听器,修改对象里面任何一个属性都会触发监听器里的 handler 函数。
在实际开发过程中,用户很可能只需要监听对象中的某几个属性,设置 deep:true 之后就会增大程序性能的开销。这里可以直接监听想要监听的属性,例如修改上面的示例,只监听 score 属性。
【实例四】监听器对象的单个属性。
<div id="app"> 商品产地:<input type="text" v-model="goods.city"> <p>{{pess}}</p> </div> <!--引入Vue文件--> <script src="https://unpkg.com/vue@next"></script> <script> //创建一个应用程序实例 const vm= Vue.createApp({ //该函数返回数据对象 data(){ return{ pess:'', goods: { name: '洗衣机', city:'' } } }, watch: { //监听goods对象的city属性 'goods.city':{ handler: function(newValue,oldValue){ if(newValue == "上海"){ this.pess="商品的产地是上海!"; } else{ this.pess="商品的产地不是上海!"; } }, //设置为true,无论属性被嵌套多深,改变时都会调用handler函数 deep:true } } //在指定的DOM元素上装载应用程序实例的根组件 }).mount('#app'); </script>在 Chrome 浏览器中运行程序,在输入框中输入“北京”,结果如下图所示。
图 5 输入“北京”的效果
注意,监听对象的属性时,因为使用了点号(.),所以要使用单引号(' ')或双引号(" ")将其包裹起来,例如"'goods.city'"。