侦听器与计算属性有些相似,都是当他们的依赖项发生变化时触发,不同的时计算属性是这个值不存在,需要根据已有属性计算得来,侦听器顾名思义就是监视已经存在的值。计算属性不能有异步程序,侦听器中可以存在异步方法。能用computed的场合都能用watch解决,但是能用watch解决的,computed不一定能解决
第一种写在创建vue的实例的配置对象中
- 简单的侦听器
语法:
要监听的属性: function(newVal, oldVal){
逻辑
}
/**
* newVal : 就是你修改的新值
* oldVal: 旧的值
*/
如
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<input v-model="a1" type="" name="" id="" value="" />
<input v-model="a2" type="" name="" id="" value="" />
<div>a1 + a2 的值是 {{num}}</div>
</div>
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data() {
return {
a1: 2,
a2: 3,
num: ''
}
},
watch:{
a1: function(newVal, oldVal){
console.log(typeof newVal);
this.num = newVal + this.a2
}
}
})
</script>
</body>
</html>
此时效果是
Snipaste_2021-05-18_20-42-52.png
修改a1的值之后,就会立刻执行侦听器的函数,计算num的值
Snipaste_2021-05-18_20-44-33.png
- 复杂的侦听器
上面的例子中,num的初始值为空,所以页面上没有显示出num的值,这样的体验就不好,所以引出一个配置:immediate
语法:
要监听的属性:{
handler(newVal, oldVal){
},
immediate: true
}
/**
newVal : 就是你修改的新值
oldVal: 旧的值
handler: 名字固定,默认
immediate:当取值为true时,无论被监视的属性发不发生变化,都会强制执行一次回调
*/
将上面的例子修改之后就是:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<input v-model="a1" type="" name="" id="" value="" />
<input v-model="a2" type="" name="" id="" value="" />
<div>a1 + a2 的值是 {{num}}</div>
</div>
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data() {
return {
a1: 2,
a2: 3,
num: 0
}
},
watch:{
a1: {
handler(newVal, oldVal){
this.num = newVal + this.a2
},
immediate: true
}
}
})
</script>
</body>
</html>
页面一打开,num就已经显示出来了
Snipaste_2021-05-18_20-56-56.png
- 深度监听
上面的例子只是监听了普通的数据,当监听对象或者数组时,就会出现问题,对象的属性或者数组元素发生变化时,侦听器就见听不到了,所以需要使用深度监听,只需要添加一个deep属性即可
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<div>{{obj.name}}</div>
<input v-model="obj.name" type="" name="" id="" value="" />
</div>
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data() {
return {
obj: {
name: '张三'
}
}
},
watch:{
obj: {
handler(newVal, oldVal){
console.log("名字发生变化" + newVal);
},
deep: true
}
}
})
</script>
</body>
</html>
注:不能直接去监听对象的某个属性或者数组的某个元素,语法不通过的,如
watch:{
arr[0]: {
}
} // 不可以
watch:{
obj.name: {
}
} // 不可以
- 监听对象的某一个属性
将obj.xxx加上引号 => 'obj.xxx'
'obj.name': {
handler(newVal, oldVal){
console.log("名字发生变化" + newVal);
},
deep: true
}
完整程序
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<div>{{obj.name}}</div>
<input v-model="obj.name" type="" name="" id="" value="" />
</div>
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data() {
return {
obj: {
name: "张三"
}
}
},
watch:{
'obj.name': {
handler(newVal, oldVal){
console.log("名字发生变化" + newVal);
},
deep: true
}
}
})
</script>
</body>
</html>
这样就能修改成功了
Snipaste_2021-05-18_21-18-52.png
- 监听数组的某一个元素
如果使用监听对象某一个属性那样监听数组的某一个元素就会报错
Failed watching path: "arr[0]" Watcher only accepts simple dot-delimited paths. For full control, use a function instead.
翻译过来就是: 监视路径失败:“arr[0]”监视程序只接受简单的点分隔路径。要完全控制,请改用函数。
所以这里我们就可以使用计算属性,将arr[0]做成计算属性,再监听这个计算属性就ok了
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<div>{{arr[0]}}</div>
<input v-model="arr[0]" type="" name="" id="" value="" />
</div>
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data() {
return {
arr: ['1', '2']
}
},
watch:{
arrFirst: {
handler(newVal, oldVal){
console.log("名字发生变化" + newVal);
},
deep: true
}
},
computed:{
arrFirst(){
return this.arr[0]
}
}
})
</script>
</body>
</html>
Snipaste_2021-05-18_21-31-20.png
- 数组形式(vue3+)
这种方式就比较灵活了,
watch: {
(监听的数据):[处理函数1, 处理函数2, .........]
}
也就说我们通过数组的形式,可以为当前监听的数据添加多个处理函数,也可以直接调用methods中的方法,不过要引号将函数名引起来
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>{{name}}</h1>
<button @click="changeName">改名字</button>
</div>
<script src="./js/vue2.js"></script>
<script>
var vm = new Vue({
el: "#app",
data() {
return {
name: "zhangsan"
}
},
methods: {
test(){
console.log("我是test");
},
changeName(){
this.name = "王五"
}
},
watch: {
name:[
'test',
function(newVal, old){
console.log("-----------------名字改了------------------------");
}
]
}
})
</script>
</body>
</html>
第二种写在全局
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<div id="app">
...
</div>
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data() {
return {
name: "张三"
}
}
})
vm.$watch("name", function(newVal, oldVal){
// 你的逻辑
})
</script>
</body>
</html>
强调
不论是写在配置对象还是全局,侦听器的回调函数都不能用箭头函数,因为箭头函数的this在当前环境指向的是window,当你使用this时就可能没反应或者报错
网友评论