Vue.js监听器
Vue.js监听器1 监听器的定义与使用Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动:监听属性。**当有一些数据需要随着其他数据变化而变动时,就可以使用监听器。**听起来监听器和计算属性差不多,从功能描述来看,确实是,不过在实际应用中二者还是有很大差别。下面来介绍一下监听器的使用,以及和计算属性的区别。1.1 监听器基本使用监听器是在Vue实例的选项对象的watch选项中定义的。
1 监听器的定义与使用
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动:监听属性。当有一些数据需要随着其他数据变化而变动时,就可以使用监听器。 听起来监听器和计算属性差不多,从功能描述来看,确实是,不过在实际应用中二者还是有很大差别。下面来介绍一下监听器的使用,以及和计算属性的区别。
1.1 监听器基本使用
监听器是在Vue实例的选项对象的watch选项中定义的。下面通过监听器来实现千米与米之间的换算。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01 监听器的定义与使用</title>
</head>
<body>
<div id="app">
千米:<input type="text" v-model="kilometers">
米:<input type="text" v-model="meters">
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
// 初始化为0
kilometers: 0,
meters: 0
},
// 监听器定义与使用(是以函数的形式,可以最多有两个参数,val oldVal)
watch: {
kilometers: function (val) {
this.meters = val * 1000;
},
// 监听器可以接受两个参数,val是当前值,oldVal是改变之前的值
meters: function (val, oldVal) {
this.kilometers = val / 1000;
}
}
});
</script>
</body>
</html>
上面编写了两个监听器,分别监听数据属性kolimeters和meters变化,当其中一个数据属性发生改变时,对应的监听器就会被调用,经过计算得到另一个数据属性的值。浏览器中显示的效果如下:
注意事项:
1、不要使用箭头函数来定义监听器函数,例如下面的代码:
kilometers: (val) => {
this.kilometers = val;
this.meters = this.kilometers * 1000;
}
因为箭头函数中的this指向的是最近一层非箭头函数中this的指向,本例中箭头函数外面没有非箭头函数,因此箭头函数中this指向window对象,this.kilometers和this.meters都是undefined。
2、监听器还可以通过Vue实例方法来写(不推荐)。
vm.$watch('kilometers', function (val, oldVal) {
this.meters = val * 1000;
});
vm.$watch('meters', function (val, oldVal) {
this.kilometers = val / 1000;
})
1.2 监听器的更多形式
1.2.1 监听器接方法名
监听器在定义时,除了直接写一个函数外,还可以接一个方法名。如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02 监听器的更多形式-接方法名</title>
</head>
<body>
<div id="app">
年龄:<input type="text" v-model="age">
<span v-show="info">{{info}}</span>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
// 年龄默认值为0
age: 0,
// 空字符串进行布尔判断时是false,所以初始不显示
info: ''
},
methods: {
checkAge() {
if (this.age >= 18) {
this.info = "已成年";
} else {
this.info = "未成年";
}
}
},
watch: {
// 监听器接方法名,但要使用引号引起来
age: 'checkAge'
}
})
</script>
</body>
</html>
在浏览器中运行效果如下:
1.2.2 监听一个对象属性的变化
监听器还可以监听一个对象的属性变化,代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03 监听器的更多形式-监听一个对象属性的变化</title>
</head>
<body>
<div id="app">
<!--监听person对象的age属性-->
年龄:<input type="text" v-model="person.age">
<!--这里使用v-if也可以-->
<span v-show="info">{{info}}</span>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
person: {
name: "steve",
age: 0
},
info: ''
},
// 正确写法
watch: {
person: {
// handler用于定义当数据变化时调用的监听器函数
// val是当前值,oldVal是改变之前的值,二者都是person对象
handler: function (val, oldVal) {
if (val.age >= 18) {
this.info = "已成年";
} else {
this.info = "未成年";
}
},
// 表示只要person对象中的属性发生变化,就调用handler()方法,无论该属性嵌套有多深。
deep: true,
}
}
// 错误写法
// watch: {
// 监听对象时,必须使用handler方法
// person: function (val) {
// if (val.age >= 18) {
// this.info = "已成年";
// } else {
// this.info = "未成年";
// }
// }
// }
})
</script>
</body>
</html>
在浏览器中运行结果与上面一致。
注意事项:
1、监听器函数在初始渲染时并不会被调用,只有在后续监听的属性发生变化时才会被调用;如果要让监听器函数在监听后立即执行,可以使用immediate选项,设为true。例如:
watch: {
person: {
handler: function (val, oldVal) {
if (val.age >= 18) {
this.info = "已成年";
} else {
this.info = "未成年";
}
},
deep: true,
// 监听器函数在初始渲染时并不会被调用,只有在后续监听的属性发生变化时才会被调用;如果要让监听器函数在监听后立即执行,可以使用immediate选项,设为true。
immediate: true
}
}
当页面加载后,由于age初始值为0,因此会立即显示“未成年”。
2、如果仅仅监听对象的一个属性,且变化也不影响对象的其他属性,那么没必要像上面那么麻烦,直接监听该对象的属性即可,如下所示:
watch: {
// 直接监听person对象的age属性
// person.age中有个特殊字符点号,用单引号括起来即可,单引号不可去除。
'person.age': function (val) {
if (val >= 18) {
this.info = "已成年";
} else {
this.info = "未成年";
}
}
}
2 监听器与计算属性的区别
2.1 实例
当需要在数据变化时执行异步或开销较大的操作时,使用监听器是最合适的。例如在一个在线问答系统中,用户输入的问题需要到服务端获取答案,就可以考虑对问题属性进行监听,在异步请求答案的过程中,可以设置中间状态,向用户提示“请稍后”,这样的功能使用计算属性就无法做到了。下面使用监听器实现Fibonacci数列计算的例子,斐波那契数列计算比较耗时(递归),采用HTML5新增的WebWorker来计算。将斐波那契数列计算单独放到一个js文件中(Worker线程),页面显示放到html文件中(主线程)。
fibonacci.js(Worker线程)
function fibonacci(n) {
// arguments为函数内部对象,包含传入函数的所有参数;arguments.callee代表函数名,多用于递归,这里便是递归调用。
return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2);
}
onmessage = function (event) {
// 事件对象的data属性可以获取主线程发来的数据,radix是“进制”的意思,10表示十进制
var num = parseInt(event.data, 10);
// 调用计算斐波那契数列的函数,并传入参数,并将计算结果发送给主线程
postMessage(fibonacci(num));
}
接下来是主页面(主线程),代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04 监听器结合WebWorker</title>
</head>
<body>
<div id="app">
请输入要计算斐波那契数列的第几个数:
<input type="text" v-model="num">
<p v-show="result">{{result}}</p>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
num: 0,
// 初始值为空字符串,不显示
result: '',
},
watch: {
num: function (val) {
this.result = "请稍后...";
if (val > 0) {
// 主线程采用new命令,调用Worker()构造函数(参数是一个脚本文件,该文件就是Worker线程所要执行的任务),新建一个Worker线程。
let worker = new Worker("fibonacci.js");
// 主线程调用worker.postMessage()方法(方法的参数就是主线程传给Worker线程的数据),向Worker线程发送消息。
worker.postMessage(val);
// 接着主线程通过worker.onmessage指定监听函数,结束子线程发回来的消息。事件对象的data属性可以获取Worker线程发来的数据。
worker.onmessage = (event) => this.result = event.data;
} else {
// 小于等于0的输入显示“不合法”
this.result = '不合法的输入';
}
}
}
});
</script>
</body>
</html>
运行效果:
中间状态:输入斐波那契数列第40个数,程序开始递归运算,这个过程比较耗费时间,故设置一个中间状态“请稍后”。
最终结果:
说明:
1、斐波那契数列计算耗时,所以设置了一个中间状态,给用户一个提示。
2、注意主页面中箭头函数的使用,其中this指向的是最近一层非箭头函数中this的指向,即监听器num,此时this指向该Vue实例vm,指向正确。在Vue开发过程中,经常会遇到this指向问题,合理地使用箭头函数可以避免很多问题。
2.2 总结
监听器与计算属性的区别是,监听器不需要返回新的数据,不能被当作数据属性使用,当需要在数据变化时执行异步或开销较大的操作时,使用监听器是最合适的。
更多推荐
所有评论(0)