一、什么是属性
如下图,对Vue来说
data中所写的就是属性,即黄色框
蓝色框——属性名
白色框——属性值
二、计算属性
计算属性是一种在编程中常用的概念,它是指一个属性的值不是直接存储在内存中,而是通过计算得出的属性。在访问这种属性时,通常会执行一段特定的代码来计算并返回属性的值,而不是简单地返回预先存储的数值。
计算属性的值通常依赖于当前对象的状态或其他相关属性的值,因此每次访问计算属性时都会重新计算并返回最新的值。这种方式使得我们可以在获取属性值的同时执行一些复杂的逻辑或计算,从而实现更灵活和高效的编程。
在很多编程语言中,如JavaScript、Python、Swift等,都提供了计算属性的机制,开发者可以根据需要定义计算属性来简化代码,并实现更复杂的数据处理逻辑。
1、计算属性的位置
data中的属性和computed中的计算属性都在vm中(Vue实例)
(1)、验证计算属性在vm中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span></span><br>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed:{
fullName:{
//get有什么用
//当有人读取fullName时,会自动调用get方法,并返回fullName的值
get(){
console.log('get方法被调用了')
return '一二三'
}
}
}
})
</script>
</html>
打开网页,右键点击检查,打开控制台,输入vm
展开Vue
点击三个点,这个过程就是读取过程,控制台则会输出语句:get方法被调用了
由此我们可以知道,计算属性在vm中
(2)、vm._data中没有计算属性
同样的方式打开控制台,分别输入:vm._data.firstName、vm._data.lastName、vm._data.fullName
由此可知,vm._data中没有计算属性
(3)、正确写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}</span><br>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed:{
fullName:{
//get有什么用
//当有人读取fullName时,会自动调用get方法,并返回fullName的值
//什么时候调用get
//1、初次读取fullName时候2、所依赖数据发生变化时
get(){
console.log('get方法被调用了')
// return '一二三'
return this.firstName + this.lastName
}
}
}
})
</script>
</html>
注意get中this的用法
(4)、set的用法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed:{
fullName:{
//get有什么用
//当有人读取fullName时,会自动调用get方法,并返回fullName的值
//什么时候调用get
//1、初次读取fullName时候2、所依赖数据发生变化时
get(){
console.log('get方法被调用了')
// return '一二三'
return this.firstName + '-' +this.lastName
},
//set有什么用
//当有人修改fullName时,会自动调用set方法,并将修改后的值作为参数传入
//什么时候调用set
//1、修改fullName时候
set(value){
console.log('set方法被调用了',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})
</script>
</html>
2、相比较与methods,计算属性的优势
计算属性具有缓存功能,而methods没有
计算属性:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
全名:<span>{{fullName}}</span><br>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed:{
fullName:{
//get有什么用
//当有人读取fullName时,会自动调用get方法,并返回fullName的值
//什么时候调用get
//1、初次读取fullName时候2、所依赖数据发生变化时
get(){
console.log('get方法被调用了')
// return '一二三'
return this.firstName + this.lastName
}
}
}
})
</script>
</html>
methods:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName()}}</span><br>
全名:<span>{{fullName()}}</span><br>
全名:<span>{{fullName()}}</span><br>
全名:<span>{{fullName()}}</span><br>
全名:<span>{{fullName()}}</span><br>
全名:<span>{{fullName()}}</span><br>
全名:<span>{{fullName()}}</span><br>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
methods: {
fullName() {
console.log('fullName被调用了')
return this.firstName + this.lastName
}
}
})
</script>
</html>
3、总结
计算属性:
1、定义:要用的属性不存在,要用已有的属性计算得来
2、原理:底层借助了Object.defineproperty方法提供的getter和setter
3、get函数什么时候执行
(1)、初次读取时候会执行一次
(2)、当依赖的数据发生变化时,会被再次调用
4、优势:相比methods,内部有缓存机制(复用),效率更高,调用方便
5、备注:
(1)、计算属性最终会出现在vm上,直接读取使用即可
(2)、如果计算属性要被修改,那必须写set函数去响应修改,且set函数中要引起计算时依赖的数据发生变化
4、计算属性简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}</span><br>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed:{
//完整写法
// fullName:{
// get(){
// console.log('get方法被调用了')
// return this.firstName + '-' +this.lastName
// },
// set(value){
// console.log('set方法被调用了',value)
// const arr = value.split('-')
// this.firstName = arr[0]
// this.lastName = arr[1]
// }
// }
//简写法
fullName(){
console.log('get方法被调用了')
return this.firstName + '-' + this.lastName
}
}
})
</script>
</html>
直接把fullName当作get函数使用
三、监视属性
1、监视属性的写法
(1)、什么是监视属性
监视属性是Vue实例中的一个选项,用于观察指定数据的变化。 当被监视的数据发生变化时,监视属性会执行相应的操作,例如调用函数、触发事件等。 通过监视属性,您可以实现对数据的定制化操作和响应。
监视属性——watch
(2)、案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot:true ,
},
computed: {
info() {
return this.isHot? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
watch:{
isHot:{
immediate:true,//初始化时立即调用handler函数
//handler什么时候调用?当isHot值发生变化时,调用handler函数
handler(newVal,oldVal){
console.log(`天气变了,现在是${newVal?'热':'冷'}`);
}
}
},
})
</script>
</html>
immediate是初始化时是否立即调用handler函数,true就是调用,false就是不调用
handler当isHot值发生变化时调用,具有新值(newVal)和旧值(oldVal)
运行结果如下图:
(3)另一种方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot:true ,
},
computed: {
info() {
return this.isHot? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
// watch:{
// isHot:{
// immediate:true,//初始化时立即调用handler函数
// //handler什么时候调用?当isHot值发生变化时,调用handler函数
// handler(newVal,oldVal){
// console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
// }
// }
// },
})
vm.$watch('isHot',{
immediate: true,
handler(newVal, oldVal) {
console.log('info变化了', newVal, oldVal)
}
})
</script>
</html>
什么时候使用这两种方法呢?
第一种方法:创建Vue实例的时候很明确要监视的对象
第二种方法:创建Vue实例的时候不知道监视谁,后续根据用户的一些行为知道要监视,再调API
(4)、计算属性也能被监视
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot:true ,
},
computed: {
info() {
return this.isHot? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
watch:{
info:{
immediate:true,//初始化时立即调用handler函数
//handler什么时候调用?当isHot值发生变化时,调用handler函数
handler(newVal,oldVal){
console.log(`info变了,`,'现在是',newVal,',之前是',oldVal);
}
}
},
})
</script>
</html>
(5)、注意
当监视属性不存在的时候,不会报错,newVal和oldVal会显示undefined
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot:true ,
},
computed: {
info() {
return this.isHot? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
// watch:{
// isHot:{
// immediate:true,//初始化时立即调用handler函数
// //handler什么时候调用?当isHot值发生变化时,调用handler函数
// handler(newVal,oldVal){
// console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
// }
// }
// },
})
vm.$watch('abc',{
immediate: true,
handler(newVal, oldVal) {
console.log('info变化了', newVal, oldVal)
}
})
</script>
</html>
2、深度监视
(1)、案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
<h3>a的值是:{{numbers.a}}</h3>
<button @click="numbers.a++">点我让a++</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot: true,
numbers:{
a:1,
b:1,
}
},
computed: {
info() {
return this.isHot ? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
watch:{
isHot:{
// immediate:true,//初始化时立即调用handler函数
//handler什么时候调用?当isHot值发生变化时,调用handler函数
handler(newVal,oldVal){
console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
}
},
//监视多级结构中某个属性的变化
'numbers.a':{
handler(newVal,oldVal){
console.log(`a的值变了,`,'现在是',newVal,',之前是',oldVal);
}
}
},
})
</script>
</html>
注意:
在写watch监视a的时候,不能直接写a,要写numbers.a,且要加单引号
(2)、案例2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
<h3>a的值是:{{numbers.a}}</h3>
<button @click="numbers.a++">点我让a++</button>
<h3>b的值是:{{numbers.b}}</h3>
<button @click="numbers.b++">点我让b++</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot: true,
numbers:{
a:1,
b:1,
}
},
computed: {
info() {
return this.isHot ? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
watch:{
isHot:{
// immediate:true,//初始化时立即调用handler函数
//handler什么时候调用?当isHot值发生变化时,调用handler函数
handler(newVal,oldVal){
console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
}
},
//监视多级结构中某个属性的变化
// 'numbers.a':{
// handler(newVal,oldVal){
// console.log(`a的值变了,`,'现在是',newVal,',之前是',oldVal);
// }
// }
numbers:{
deep:true,
handler(){
console.log('numbers发生了变化')
}
}
},
})
</script>
</html>
注意deep的用法(总结中有)
(3)、总结
深度监视:
1、Vue中的watch默认不监视对象内部值的改变(一层)
2、配置deep:true可以监视对象内部值的改变(多层)
备注:
1、Vue自身可以监视对象内部值的改变,但Vue提供的watch默认不可以
2、使用watch时根据数据的具体结构,决定是否采用深度监视
3、监视属性的简写
(1)第一种方法的简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot: true,
},
computed: {
info() {
return this.isHot ? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
watch:{
//正常写法
// isHot:{
// //immediate:true,
// // deep:true,
// handler(newVal,oldVal){
// console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
// }
// },
//简写
isHot(newVal,oldVal){
console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
}
},
})
</script>
</html>
函数名即为监视对象,函数就当handler使用
(2)、第二种方法的简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src=https://cdn.bootcss.com/vue/2.7.16/vue.js></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script>
Vue.config.productionTip = false;//阻止vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
isHot: true,
},
computed: {
info() {
return this.isHot ? '热' : '冷'
}
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
watch:{
//正常写法
// isHot:{
// //immediate:true,
// // deep:true,
// handler(newVal,oldVal){
// console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
// }
// },
//简写
// isHot(newVal,oldVal){
// console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
// }
},
})
//正常写法
// vm.$watch('isHot',{
// immidiate:true,
// deep:true,
// handler(newVal,oldVal){
// console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
// }
// })
简写
vm.$watch('isHot',function(newVal,oldVal){
console.log(`天气变了,`,'现在是',newVal,',之前是',oldVal);
})
</script>
</html>
注意:如果函数写成箭头函数的形式,this指向会有所不同
四、计算属性和监视属性的对比
computed和watch之间的对比:
1、computed能完成的功能,watch都能完成
2、watch能完成的功能,computed不能完成,例如:watch可以进行异步操作
两个重要的原则:
1、所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
2、所有不被Vue管理的函数(定时器的回调函数、ajex的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象