本章节,我们将为大家介绍 Vue 监听属性 watch,我们可以通过 watch 来响应数据的变化。
以下实例通过使用 watch 实现计数器:
<div id = "app">
<p style = "font-size:25px;">计数器: {{ counter }}</p>
<button @click = "counter++" style = "font-size:25px;">点我</button>
</div>
<script>
const app = {
data() {
return {
counter: 1
}
}
}
vm = Vue.createApp(app).mount('#app')
vm.$watch('counter', function(nval, oval) {
alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!');
});
</script>
以下实例进行千米与米之间的换算:
<head>
<meta charset="utf-8">
<title>Vue 测试实例</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id = "app">
千米 : <input type = "text" v-model = "kilometers">
米 : <input type = "text" v-model = "meters">
</div>
<p id="info"></p>
<script>
const app = {
data() {
return {
kilometers : 0,
meters:0
}
},
watch : {
kilometers:function(val) {
this.kilometers = val;
this.meters = this.kilometers * 1000
},
meters : function (val) {
this.kilometers = val/ 1000;
this.meters = val;
}
}
}
vm = Vue.createApp(app).mount('#app')
vm.$watch('kilometers', function (newValue, oldValue) {
// 这个回调将在 vm.kilometers 改变后调用
document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
})
</script>
以上代码中我们创建了两个输入框,data属性中,kilometers 和 meters 初始值都为0。watch 对象创建了 data 对象的两个监控方法:kilometers 和 meters。
使用场景
watch(异步场景),computed(数据联动)watch可以在所监听的数据后面直接加字符串形式的方法名
<!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>Vue计算属性/侦听器/方法比较</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>计算属性:computed</h1>
{{fullName}}
<h1>方法:methods</h1>
{{fullName2()}}
<h1>侦听器:watch</h1>
{{watchFullName}}
<h1>年龄</h1>
{{age}}
</div>
<script>
var other = 'This is other';
var app = new Vue({
el:"#app",
data:{
firstName:"zhang",
lastName:"san",
watchFullName:"zhangsan",
age:18,
},
watch: {
firstName:function(newFirstName, oldFirstName){
console.log("firstName触发了watch,newFirstName="+newFirstName+",oldFirstName="+oldFirstName)
this.watchFullName = this.firstName+this.lastName+","+other
},
lastName:function(newLastName, oldLastName){
console.log("lastName触发了watch,newLastName="+newLastName+",oldLastName="+oldLastName)
this.watchFullName = this.firstName+this.lastName+","+other
},
watchFullName:"change"
},
computed: {
fullName:function(){
console.log("调用了fullName,计算了一次属性")
return this.firstName+this.lastName+","+other;
}
},
methods: {
fullName2:function(){
console.log("调用了fullName,执行了一次方法")
fullName2 = this.firstName+this.lastName+","+other;
return fullName2;
},
change(){
console.log("调用了change,触发了watch")
return this.watchFullName='111'
}
}
});
</script>
</body>
</html>
handler方法就相当于普通侦听器触发的事件,从结果可以看到,组件初始化的时候,侦听器并没有handler方法,所以fullName是没有值的。
当修改以上代码,加上immediate:true,immediate:true代表watch里面声明了之后会立马执行handler里面的函数。执行相应的逻辑。组件初始化的时候,侦听器(immediate)触发handler方法
<!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>Vue计算属性/侦听器/方法比较</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<p>FullName: {{person.fullname}}</p>
<p>FirstName: <input type="text" v-model="person.firstname"></p>
</div>
</div>
<script>
var other = 'This is other';
var app = new Vue({
el: '#app',
data(){
return {
person: {
firstname: 'Menghui',
lastname: 'Jin',
fullname: ''
}
}
},
watch: {
person: {
handler(n,o){
this.person.fullname = n.firstname + '' + this.person.lastname;
},
immediate: true, //刷新加载 立马触发一次handler
deep: true // 可以深度检测到 person 对象的属性值的变化
}
}
})
</script>
</body>
</html>
当在输入框中输入数据时,可以发现fullName的值并没有随之改变 这是因为vue无法检测到对象内部属性值的变化,比如person。firstname的变化
所以此时 需要用到vue的深度监听(deep)
此时加上代码 deep:true
可以发现 每次输入框数据变化 fullname 随之改变
上面的可以发现handler监听的新值和老值是一样的 这是由vue2.0的坑 由于同源导致的 可以用computed 来修改
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<p>FullName: {{person.fullname}}</p>
<p>FirstName: <input type="text" v-model="person.firstname"></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
person: {
firstname: 'Menghui',
lastname: 'Jin',
fullname: ''
}
}
},
methods: {
},
computed: {
person2(){
return JSON.parse(JSON.stringify(this.person));
}//解决深度监听新老值同源问题
},
watch:{
person2:{
handler(n,o){
console.log(this.person);
console.log(n.firstname);
console.log(o.firstname);
/* this.person.fullname = this.person.firstname + this.person.lastname */
},
/* immediate: true, */
deep: true // 可以深度检测到 person 对象的属性值的变化
}
}
})
</script>
</body>
</html>