1. 作用
监视数据变化,执行一些业务逻辑或异步操作。
2. 格式
监听器 watch 内部以 key :value 的形式定义,key 是 data 中的属性名,value 是监听到 key 变化后执行的回调函数。value 可以是字符串,可以是函数,可以是对象。
- value 如果为字符串,字符串为方法名称,需要通过 methods 定义好;
- value 如果为函数,通过函数可以获取到监听对象更新前和更新后的值;
- value 如果为对象,对象内可以包含回调函数的其他选项,例如是否初始化时进行监听 immediate : true,或是否执行深度遍历 deep : true。
如 value 为函数,watch 格式为:
watch: {
// 该方法会在数据变化时,触发执行
// data 中属性的名称为数据属性名
// : function 可以省略。数据属性名 : function (newValue, oldValue) 可简写为 数据属性名 (newValue, oldValue)
数据属性名 : function (newValue, oldValue) {
一些业务逻辑 或 异步操作。
},
// data 中对象数据的属性需要写为 对象.属性名
'对象.属性名' : function (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
}
如 value 为对象,watch 格式为:
watch: {
数据属性名 : {
deep: true, // 深度监视(针对复杂类型)
immediate: true, // 是否立刻执行一次handler
handler (newValue) {
console.log(newValue)
}
}
}
3. 示例
3.1 value 值为字符串
<!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>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<div class="input-wrap">
<textarea v-model="words"></textarea>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
words: ''
},
methods:{
changewords(){
console.log(this.words)
}
},
watch: {
words : 'changewords' // 注意单引号不要漏掉
}
})
</script>
</body>
</html>
执行结果:
3.2 value 值为函数
将上面代码改写成 value 值为函数的格式:
<!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>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<div class="input-wrap">
<textarea v-model="words"></textarea>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
words: ''
},
watch: {
words (newvalue, oldvalue) {
console.log(newvalue)
}
}
})
</script>
</body>
</html>
执行结果:
3.3 value 值为对象
将上面代码改写成 value 值为对象的格式:
<!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>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<div class="input-wrap">
<textarea v-model="words.cat"></textarea>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
words: {
cat : '奶牛猫',
dog : '哈士奇',
}
},
watch: {
// '对象.属性名'的单引号不要漏掉
'words.cat' : {
deep : true,
immediate : true, // 立刻执行一次handler
handler (newvalue) {
console.log(newvalue)
}
}
}
})
</script>
</body>
</html>
执行结果:
因为设置了 immediate : true,所以首次打开页面会打印出 “奶牛猫” 字样。
4. 与计算属性对比
计算属性的结果会缓存,只有依赖属性发生变化才会重新计算,且必须返回一个数据,主要用来进行数据计算。
监听器主要监听某个数据的变化,从而执行回调业务,不仅仅局限于返回数据,比如数据变化时执行异步发送Ajax请求或开销较大的操作时,采用监听器较好。