什么是 watch 侦听器
watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。
语法格式如下:
使用 watch 检测用户名是否可用
监听 username 值的变化,并使用 axios 发起 Ajax 请求,检测当前输入的用户名是否可用:
watch: {
// 监听 username 值的变化
async username(newVal) {
if (newVal === '') return
// 使用 axios 发起请求,判断用户名是否可用
const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
console.log(res)
}
}
侦听器格式
- 方法格式的侦听器
- 缺点1:无法在刚进入页面的时候,自动触发
- 缺点2:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器
- 对象格式的侦听器
- 好处1:可以通过 immediate 选项,让侦听器自动触发
- 好处2:可以通过 deep 选项,让侦听器深度监听对象中每个属性的变化
immediate 选项
默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使 用 immediate 选项。示例代码如下:
watch: {
username: {
// handler 是固定写法,表示当 username 的值变化时,自动调用 handler 处理函数
handler(newVal,oldVal){
console.log(newVal,oldVal)
},
// 表示页面初次渲染好之后,就立即触发当前的 watch 侦听器
//immediate 选项的默认值是 false
immediate: true
}
}
deep 选项
如果 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选 项,代码示例如下:
<body>
<div class="app">
<input type="text" v-model="username">
</div>
<script>
const vm = new Vue({
el:'.app',
data:{
info:{
username:'admin'
}
},
// 所有侦听器都应该被定义到 watch 节点下
watch:{
info:{
handler(newVal){
console.log(newVal)
},
// 开启深度监听,只要对象中任何一个属性变化了,都会触发对象的侦听器
}
}
})
</script>
</body>
监听对象单个属性的变化
如果只想监听对象中单个属性的变化,则可以按照如下的方式定义 watch 侦听器:
<body>
<div class="app">
<input type="text" v-model="info.username">
</div>
<script>
const vm = new Vue({
el:'.app',
data:{
info:{
username:'admin'
}
},
// 所有侦听器都应该被定义到 watch 节点下
watch:{
// 如果要侦听的是对象的子属性的变化,则必须包裹一层单引号
'info.username'(newVal) {
console.log(newVal)
}
}
})
</script>
</body>
计算属性
什么是计算属性
计算属性指的是通过一系列运算之后,最终得到一个属性值。 这个动态计算出来的属性值可以被模板结构或 methods 方法使用。示例代码如下:
特点:
- 定义的时候,要被定义为方法
- 在使用计算属性的时候,当普通的属性使用即可
好处:
- 实现了代码的复用
- 只要计算属性中依赖的数据源变化了,则计算属性会自动重新求值
利用计算属性写一个rgba颜色生成器
<!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>rgba颜色生成器</title>
<script src="vue-2.6.12.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
.Color {
width: 200px;
height: 200px;
position: absolute;
top: 150px;
right: 100px;
clip-path: polygon(50% 0%, 83% 12%, 100% 43%, 94% 78%, 68% 100%, 32% 100%, 6% 78%, 0% 43%, 17% 12%);
}
.app {
position: relative;
width: 400px;
height: 500px;
border: 3px solid #828584;
margin: 100px auto;
border-radius: 15px;
padding: 15px;
box-sizing: border-box;
}
input {
width: 45px;
height: 50px;
font-size: 20px;
outline: none;
border-radius: 5px;
border: 1px solid #00f9e5;
text-align: center;
color: #00f9e5;
background-color: black;
}
p {
text-align: center;
margin-top: 250px;
}
.top {
width: 100%;
display: flex;
justify-content: space-around;
}
.txt {
display: flex;
justify-content: space-around;
font-size: 30px;
margin-bottom: 5px;
color: #206f9c;
}
</style>
</head>
<body>
<div class="app">
<div class="txt"><span>R</span><span>G</span><span>B</span><span>A</span></div>
<div class="top">
<input type="text" v-model.number="r">
<input type="text" v-model.number="g">
<input type="text" v-model.number="b">
<input type="text" v-model.number="a">
</div>
<div class="Color" :style="{backgroundColor:rgba}"></div>
<p>{{rgba}}</p>
</div>
<script>
const vm = new Vue({
el:'.app',
data:{
r:0,g:0,b:0,a:0.5
},
computed:{
rgba(){
return `rgba(${this.r},${this.g},${this.b},${this.a})`
}
}
})
</script>
</body>
</html>