一、计算属性
1. 案例引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br><br>
名:<input type="text" v-model="lastName"><br><br>
<!--只取姓的前 3 位-->
姓名:<span>{{firstName}} - {{lastName.slice(0, 3)}}</span>
</div>
<script>
new Vue({
el:'#root',
data:{
firstName:'',
lastName:''
}
})
</script>
</body>
</html>
上述案例中需要输入姓与名,然后输出名的前 3 位,最先想到的就是直接在插值语法中使用 slice 函数。
但这样就违背了官网“模板表达式便利”的前提,如下图:
2. 计算属性使用
计算属性完整语法:
computed:{
计算属性名:{
// 返回值作为 计算属性名的值
get(){
return "";
},
set(value){
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性案例引入</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br><br>
名:<input type="text" v-model="lastName"><br><br>
<!--只取姓的前 3 位-->
姓名:<span>{{fullName}}</span>
</div>
<script>
new Vue({
el:'#root',
data:{
firstName:'',
lastName:''
},
computed:{
fullName:{
// 返回值作为 fullName 的值
get(){
return this.firstName + '-' + this.lastName
},
set(value){
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})
</script>
</body>
</html>
注意:
- 计算属性与data属性都是Vue中属性,不能重名,用法相同
- 计算属性通过已有属性计算得来
- 如果计算属性要被修改,那必须写
set
函数去响应修改,且set中要引起计算时依赖的数据发生改变
get函数执行时机
- 初次读取时会执行一次
- 当依赖的数据发生改变时会被再次调用
3. 计算属性缓存
计算属性是基于它们的依赖项的值进行缓存的,只要依赖项的值不变,除第一次读取外,均是从缓存读取值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性案例引入</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>{{name}}</h1>
</div>
<script>
new Vue({
el:'#root',
computed:{
name:{
get(){
console.log("get...");
return "划水艺术家";
},
set(value){
}
}
}
})
</script>
</body>
</html>
计算属性根据依赖项的值缓存,依赖项的值变化后重新存入缓存,比普通方法性能更高
4. 计算属性简写
语法:
computed:{
计算属性名(){
return "";
}
}
计算属性确定不考虑修改,可以使用计算属性的简写形式。
二、监听属性
1. 案例引入
<!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>监听属性</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>今天天气好{{isHot ? '炎热' : '凉爽'}}!</h1>
<button @click="changeWeather">点击切换天气</button>
</div>
<script>
new Vue({
el:'#root',
data:{
isHot:true,
},
methods:{
changeWeather(){
this.isHot = !this.isHot
}
}
})
</script>
</body>
</html>
上述案例中需要根据 isHot 的值判断是否炎热,但上述方法略显草率,也许我们可以用刚才学的计算属性来试一试。
<!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>监听属性</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>今天天气好{{info}}!</h1>
<button @click="changeWeather">点击切换天气</button>
</div>
<script>
new Vue({
el:'#root',
data:{
isHot:true,
},
methods:{
changeWeather(){
this.isHot = !this.isHot
}
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽';
}
}
})
</script>
</body>
</html>
这样写也不是不可以,但是我们现在要使用更适合此处需求的方式:使用监听属性
2. 监听属性使用
监听属性完整语法:
watch:{
监听属性名:{
// 当为 true 时,初始化时让 handler 调用一下,默认 false
// immediate: true,
// 当为 true 时,开启深度监视,默认 false
// deep: true,
// 当 监听属性 被修改时调用
hander(newValue, oldValue){
}
}
}
<!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>监听属性</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>今天天气好{{info}}!</h1>
<button @click="changeWeather">点击切换天气</button>
</div>
<script>
new Vue({
el:'#root',
data:{
isHot:true,
info:""
},
methods:{
changeWeather(){
this.isHot = !this.isHot
}
},
watch:{
isHot: {
immediate: true,
handler(newValue, oldValue){
this.info = newValue ? "炎热" : "凉爽";
}
}
}
})
</script>
</body>
</html>
3. 深度监听
案例引入
<!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>深度监视</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h3>a = {{numbers.a}}</h3>
<button @click="numbers.a++">点我让a+1</button>
<h3>b = {{numbers.b}}</h3>
<button @click="numbers.b++">点我让b+1</button>
</div>
<script>
new Vue({
el:'#root',
data:{
numbers:{
a:1,
b:1,
}
},
watch:{
numbers:{
handler(){
console.log('numbers改变了')
}
}
}
})
</script>
</body>
</html>
此案例是为了监视 numbers 中值的变化,但 a、b 都修改了,handler却没有调用。这是因为 Vue 中提供的 watch 默认不能监控多级结构属性变化,需要加上属性 deep:true
才可。
watch:{
//监视多级结构中所有属性的变化
numbers:{
deep:true,
handler(){
console.log('numbers改变了')
}
}
}
- Vue中的watch默认不监测对象内部值的改变(一层)
- 在watch中配置
deep:true
可以监测对象内部值的改变(多层)
4. 监听属性简写
语法:
watch:{
// 直接将此函数当为 hanlder 用
监听属性名(){
}
}
监听属性确定不需要配置 immediate
以及 deep
,可以使用监听属性的简写形式。
三、计算属性与监听属性对比
- 计算属性的依赖项的值改变后重新计算结果更新DOM,然后存入缓存
- 监听属性是监听属性值,当配置的属性值变化时调用相对应的 hanlder 函数
- 计算属性
不能执行异步任务
。计算属性一般不用来向服务器发送请求或执行异步任务,因为耗时太长。 - 最后一句话:计算属性能实现的,监听属性都能实现,计算属性不能实现的,监听属性也能实现。