1. 前言
2. 解释
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。 — 官方定义
3. 使用侦听器
前面我们介绍了什么是侦听器 watch
,那么如何定义一个侦听器呢?
侦听器 watch
实际是 vue
实例上的一个对象属性。当我们需要对 vue
实例上某个属性进行侦听时,我们以需要被侦听的属性名作为 watch
对象的键,以一个函数 function
作为该键的值。函数 function
接收两个参数:侦听数据变化之后的值newValue
;侦听数据变化之前的值oldValue
:
var vm = new Vue({
el: '#app',
data() {
return {
count:
}
},
watch: {
count: function(newVal, oldVal) {
// 具体处理逻辑
},
}
})
在介绍完如何定义一个侦听器之后,让我们用几个实例来学习一下如何在项目中使用侦听器。
3.1 对字符串、布尔值、数字、数组类型的监听
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body style="background-color: #ccc;">
<div id="app">
<div>商品名称:<input v-model="name"/></div>
<button v-on:click="cut">减一个</button>
购买数量{{count}}
<button v-on:click="add">加一个</button>
<button v-on:click="addCart">加入购物车</button>
<div v-for="(item, index) in list" :key="index">
{{item.name}} x{{item.count}}
</div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
name: '',
count:,
isMax: false,
list: []
},
methods: {
cut() {
this.count = this.count -
this.isMax = false
},
add() {
this.count = this.count +
},
addCart() {
this.list.push({
name: this.name,
count: this.count
})
}
},
watch: {
count: function(newVal, oldVal) {
if(newVal > ) {
this.isMax = true
}
if(newVal < ) {
this.count =
}
},
name: function() {
this.count =
this.isMax = false
},
isMax: function(newVal) {
if (newVal) {
console.log('注意:您购买的数量较大,请确认是否操作有误')
}
},
list() {
console.log('购物车数据发生改变')
}
}
})
</script>
</html>
代码第 25-49 行,我们定义了四个侦听器,分别是:
name — 对数据 name
侦听,触发时将 count
变成 0;并 将 isMax 变成 false
count — 对数据 count
侦听, 检测到 count
大于 10 时,将 isMax 变成 true,检测到 count
小于 0 的时候将 count
修改为 0。
isMax — 对数据 isMax 侦听,触发时,判断变化后的值是否为 true,当值为 true 时弹出提示消息
list — 对数据 list 侦听,每次改变时弹出提示消息。
3.2 示例二:侦听对象某个属性的变化
上面在示例一中学习了对字符串、布尔值、数字、数组类型的侦听,那么如何对对象的某个属性进行侦听呢?
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body>
<div id="app">
<div>商品名称:<input v-model="product.name"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
product: {
name: ''
}
},
watch: {
product: function(newValue){
console.log(newValue)
}
}
})
</script>
</html>
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body>
<div id="app">
<div>商品名称:<input v-model="product.name"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
product: {
name: ''
}
},
watch: {
product: function(newValue){
console.log(newValue)
}
},
mounted() {
this.product = {name: }
}
})
</script>
</html>
代码解释:
第 11-13 行,我们定义了侦听器 product
,并在生命周期 mounted
函数中修改 product
的值。运行代码,我们惊奇地发现侦听器会在一开始的时候触发,输入框中输入的时候同样不会触发。
大部分同学看到这里应该已经猜到之前为什么修改name
不会触发侦听器。因为product
指向的是一个引用地址,在第一个例子中,我们只修改了product
的name
属性,而没有修改product
的引用地址。而在第二个例子中,我们给 product
重新赋值,因此product
的引用地址也发生了改变,所以可以成功触发侦听器。
通过这个结论,如果只想监听 product
的 name
属性的变化,可以对代码进行如下修改:
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body>
<div id="app">
<div>商品名称:<input v-model="product.name"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
product: {
name: ''
}
},
watch: {
'product.name': function(newValue){
console.log(newValue)
}
}
})
</script>
</html>
4. 侦听器的高级用法
4.1 handler方法
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body style="background-color: #ccc;">
<div id="app">
<div>商品名称:<input v-model="name"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '方便面'
},
watch: {
name: {
handler(newVal, oldVal) {
console.log(newVal)
}
}
}
})
</script>
</html>
4.2 immediate属性
有时候你可能需要在侦听器最初绑定的时候就触发一次,这个时候我们就需要用到immediate
属性。
示例:
<!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>Document</title>
</head>
<body>
<div id="app">
<div>商品名称:<input v-model="name"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '方便面'
},
watch: {
name: {
handler(newVal, oldVal) {
console.log(newVal)
},
// 代表在wacth里声明了name这个方法之后立即先去执行一次handler方法
immediate: true
}
}
})
</script>
</html>
4.3 deep属性
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body>
<div id="app">
<div>商品名称:<input v-model="product.name"/></div>
<div>商品数量:<input v-model="product.count"/></div>
<div>商品标题:<input v-model="product.title"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
product: {
name: '',
count: '',
title: ''
}
},
watch: {
'product.name': function(newValue){
console.log(newValue)
},
'product.count': function(newValue){
console.log(newValue)
},
'product.title': function(newValue){
console.log(newValue)
}
}
})
</script>
</html>
代码解释:
在 watch
属性中,我们写了三个侦听器,都是针对 product
的某个属性进行侦听的。那有没有什么更简单的方法可以实现当 product
里面任何属性发生变化的时候就执行侦听呢?
这里就需要用到 deep
属性。deep
属性代表是否深度监听,默认值是 false。当设置为 true 时,会对对象里面的每个属性进行侦听。
示例:
<!DOCTYPE html>
<html lang="en" style="background-color: #ccc;">
<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>Document</title>
</head>
<body>
<div id="app">
<div>商品名称:<input v-model="product.name"/></div>
<div>商品数量:<input v-model="product.count"/></div>
<div>商品标题:<input v-model="product.title"/></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
product: {
name: '',
count: '',
title: ''
}
},
watch: {
product: {
handler: function(newVal) {
console.log(newVal)
},
deep: true
}
}
})
</script>
</html>
代码解释:
第 17 行,我们加了一个属性 deep
,deep
的意思就是深入观察,监听器会一层层地往下遍历,给对象的所有属性都加上这个监听器,修改对象里面任何一个属性都会触发这个监听器里的 handler。
5. 小结
本节,我们带大家学习了 侦听器watch
在 vue 项目中的运用。主要知识点有以下几点: