【 Vue全家桶 · Vue(六)】Vue框架中的监听机制之二 —— 侦听
【 Vue全家桶 · Vue(六)】Vue框架中的监听机制之二 —— 侦听
【 Vue全家桶 · Vue(六)】Vue框架中的监听机制之二 —— 侦听器watch文章目录
- 一. watch适用场景
- 二. Vue实例内部属性 watch
- 2.1 基础形式
- 2.2 一对多的实现原理
- 2.3 完整形式
- 2.3.1 watchObject 监听对象
- 2.3.2 handler 函数
- 2.3.3 deep 深度监听属性
- 2.3.4 immediate 立即执行属性
- 三. Vue实例方法 vm.$watch
- 3.1 基础形式
- 3.2 完整形式
上一篇中详细介绍了Vue框架中的计算属性computed
,我们说它常用来做数据监听,比如典型的多对一情况 —— 多数据监听和深度监听。
但这并不代表着计算属性computed
可以胜任所有的监听场景。其实Vue框架中还有一种更通用,更正统的监听方式 —— 监听器watch
。理论上他可以完成所有的监听工作。
监听器watch
的监听适用于一对多的场景,即某个组件内的一个数据的改变会影响其他多个数据。
? 拓展一下?
区别于计算属性computed
的多对一场景,有关计算属性computed
的讲解请看上一篇:
【Vue学习笔记 · 基础篇(五)】Vue框架中的监听机制之一 —— 计算属性computed
侦听器watch
有两种书写形式,分别为:
- Vue实例内部属性
watch
- Vue实例方法
vm.$watch
这两种写法本质上是等价的,需要的参数也一模一样,唯一的区别就是书写位置不同而带来的格式上的差别。所以接下来的讲解就重点以Vue实例内部属性watch
形式为例,之后vm.$watch
那一部分会给出对应的等价形式,可以对比选择。
2.1 基础形式
- watchObject(监听对象 —— data中的属性(Number / String / Boolean / Array))
- callback —— 回调函数
- newVal(非必须)—— 改变后的新值(可单选此项)
- oldVal(非必须)—— 改变前的旧值
new Vue({ el:"#app", data:{ watchObject:'' }, watch:{ watchObject:function(newVal,oldVal){ // something... } } })
来看几个简单的例子:
① 拿到改变前后的值:
比如我们在页面中添加一个输入框,使用v-model
指令双向绑定username
属性。我们希望监听该输入框的输入情况:每次输入一个字符,就在控制台打印出本次输入前后的值。
<div id="app"> <input type="text" v-model="userName"> </div>
let vm = new Vue({ el:"#app", data:{ username:'' }, watch:{ username:function(newName,oldName){ console.log(newName,oldName) } } })
② 调用methods
中的方法:
根据实际需求不同,我们也可以选择不同的参数配置。比如拿到当前变化之后的值,作为参数调用methods
中的方法func
:
new Vue({ el:"#app", data:{ watchObject:'' }, watch:{ watchObject:function(val){ this.func(val) } }, methods:{ func:function(val){ console.log(val) } } })
要注意的是回调函数中也可以只接收一个参数 —— 默认的是改变之后的值。
2.2 一对多的实现原理
仔细分析侦听器watch
的基础形式,就可以看出来他为什么适用于一对多的场景了:
① 监听对象为一个具体的实例data
属性;
言外之意就是如果你选择使用侦听器watch
来做多数据监听,那么不好意思,你只能一个一个的监听。
比如之前计算属性computed
中的两数相加add的例子:
data:{ num1:0, num2:2 }, computed:{ add:function(){ return this.num1 + this.num2 } }
侦听器watch
的版本(繁易程度显而易见):
data:{ num1:0, num2:2, result:2 }, watch:{ num1:function(val){ this.result = val + this.num2 }, num2:function(val){ this.result = val + this.num1 } }
② 回调函数体内可选择调用多个methods
中的方法;
之前计算属性computed
的getter
函数体内,必须以return
语句结尾,意思就是计算属性computed
最后都会归结到一个值上;而在侦听器watch
中就没有这个限制,可以选择调用多个methods
中的方法,即对多个数据进行操作。
computed:{ reverseMsg:function(){ return this.msg.split('').reverse().join('') } }
2.3 完整形式
侦听器watch
的完整形式包括了三个属性:handler
,deep
,immediate
。之前的基础形式就是只设置了handler
函数的完整形式的简写形式。
各属性的讲解如下:
- watchObject(监听对象 —— data中的属性(Number / String / Boolean / Array / Object))
- handler —— 回调函数
- newVal(非必须)—— 改变后的新值(可单选此项)
- oldVal(非必须)—— 改变前的旧值
- deep(非必须)—— 是否开启深度监听
- immediate(非必须)—— 是否在数据绑定阶段也执行handler函数
- handler —— 回调函数
new Vue({ el:"#app", data:{ watchObject:'' }, watch:{ watchObject:{ handler:function(newVal,oldVal){ // something... }, deep:true, immediate:true } } })
2.3.1 watchObject 监听对象
不知道你们注意到没有,这一次监听对象列表里我新添了Object
对象,就是说之前讲的基础形式不能用来监听对象内部属性。因为deep
属性默认为false
,需要我们使用完整写法来手动开启深度监听。
比如以下的监听写法就会失效:
new Vue({ el:"#app", data:{ Obj:{ username:'' } }, watch:{ Obj:function(newVal,oldVal){ console.log(newVal) } } })
2.3.2 handler 函数
handler
函数是监听到对象内任何一个属性的变化后都会执行的回调函数。要注意的是这里必须使用handler
关键字,不能为自定义函数名。
2.3.3 deep 深度监听属性
之前说过计算属性computed
中默认为深度监听,而在侦听器watch
中要想完成对对象内部属性的深度监听,就需要手动设置deep:true
。比如2.3.1中的例子可以这么写:
new Vue({ el:"#app", data:{ Obj:{ username:'' } }, watch:{ obj:{ handler:function(newVal,oldVal){ console.log(newVal) }, deep:true } } })
当然不使用deep
属性也是阔以的:在设置监听对象时,使用键路径(点访问符选择对象内部属性)。比如上例的等价形式为:
// 完整形式 watch:{ obj.username:{ handler:function(newVal,oldVal){ console.log(newVal) } } } // 基础形式 watch:{ obj.username:function(newVal,oldVal){ console.log(newVal) } }
2.3.4 immediate 立即执行属性
我们都知道监听的原理就是在发现监听对象发生变化之后会去执行某些操作。所以在没有触发监听的阶段,比如数据绑定阶段,就不会执行监听里的handler
函数。如果这个时候我们就想在数据绑定阶段也执行一次handler
函数就需要设置immediate:true
比如常见的数据初始化操作(数据绑定阶段调用初始化函数):
<div id="app"> {{Obj}}<br> <input type="text" v-model="Obj.username"> </div>
new Vue({ el:"#app", data:{ Obj:{ username:'' } }, watch:{ obj:{ handler:function(){ // 属性值为空时调用初始化函数 if(!this.Obj.username){this.initFunc()} }, deep:true, immediate:true } }, methods:{ initFunc:function(){ this.Obj.username = "zevin" } } })
Vue框架中也为我们提供了丰富的API,很多Vue实例内的属性和方法都有对应的API。附上官方API文档:
Vue官方API文档地址
vm.$watch
就是监听属性watch
的对应API,以下为官方文档的API介绍截图:
这里就不过多介绍了,用法和之前的监听属性watch
都一样,只是书写格式不同,这里就简单列出对应的基础形式和完整形式:
3.1 基础形式
- watchObject(监听对象 —— data中的属性(Number / String / Boolean / Array))
- callback —— 回调函数
- newVal(非必须)—— 改变后的新值(可单选此项)
- oldVal(非必须)—— 改变前的旧值
vm.$watch(watchObject, function (newVal, oldVal) { // something })
3.2 完整形式
- watchObject(监听对象 —— data中的属性(Number / String / Boolean / Array / Object))
- callback —— 回调函数
- newVal(非必须)—— 改变后的新值(可单选此项)
- oldVal(非必须)—— 改变前的旧值
- options —— 可选属性(对象)
- deep(非必须)—— 是否开启深度监听
- immediate(非必须)—— 是否在数据绑定阶段也执行handler函数
vm.$watch(watchObject,function () { doSomething() }, { deep:true, immediate: true } )
需要注意的区别点在于:
- 在实例外调用;
- 回调函数使用
function
关键字而不是handler
; - 最后可选属性
deep
,immediate
需要封装到对象内;