目录
注意:
监视属性:
- immediate:true;可在页面刷新时就调用一次监视。
- deep:true;可监视多层级数据(对像)的改变,深度监视。
计算属性:
<!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">
姓:<input type="text" v-model="firstName"><br><br>
名:<input type="text" v-model="lastName"><br><br>
姓名:<span>{{fullName}}</span>
</div>
<script>
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName:{
get(){
return this.firstName + '-' + this.lastName
// 或操作后再return
// const str = this.firstName + '-' + this.lastName;
// 此处对str进行逻辑处理操作
// return str
},
set(value){
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})
</script>
</body>
</html>
总结:
计算属性:
- 定义:要用的属性不存在,需要通过已有属性计算得来。
- 注意:计算属性定义的变量(属性)是内部定义方法计算return的返回值(并不是方法本身)
- 原理:底层借助了Objcet.defineproperty()方法提供的getter和setter。
计算属性什么时候被调用?(get函数什么时候执行?)
- 初次读取时会执行一次
- 当依赖的数据发生改变时会被再次调用
computed与methods区别
- 优势:与methods实现相比,内部有缓存机制可复用,效率更高,调试方便。
- 劣势:若缓存不需要使用时,计算属性造成的缓存所带来的性能消耗远比methods调用消耗大。
- methods则是每次进行数据展示都需再次调用无缓存可复用。
缓存体现举例:
data: {
firstName:"姓"
lastName:"名"
},
methods无缓存举例:
<span>1、{{fullName()}}</span>
<span>2、{{fullName()}}</span>
<span>3、{{fullName()}}</span> // 页面三处需要显示,每次显示方法都会被调用
methods: {
fullName() {
console.log("调用了"); // 打印三次
return this.firstName + this.lastName
},
}
computed缓存优势举例:
<span>1、{{fullName}}</span>
<span>2、{{fullName}}</span>
<span>3、{{fullName}}</span> // 页面三处需要显示,只首次显示调用,数据复用,节省性能消耗
computed:{
fullName:function(){
console.log("调用了"); // 打印一次
return this.firstName + this.lastName;
}
},
计算属性应用场景:当一个属性值是通过其他属性值计算而来或同一个计算得来的数据在组件内多次展示时推荐使用
备注:
- 计算属性最终会出现在vue上,直接读取使用即可
- 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
- 如果计算属性确定不考虑修改,可以使用计算属性的简写形式
计算属性简写(无需使用set()属性时的写法)
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName(){ // 此处的 fullName 是computed定义的属性 并不是方法!!!
return this.firstName + '-' + this.lastName
}
}
})
监视属性
<!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">
<h2>今天天气好{{info}}!</h2>
<button @click="changeWeather">点击切换天气</button>
</div>
<script>
Vue.config.productionTip = false
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(newValue,oldValue){ //新值 , 旧值
console.log('isHot被修改了',newValue,oldValue)
}
},
info:{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当info发生改变时
handler(newValue,oldValue){ //新值 , 旧值
console.log('info被修改了',newValue,oldValue)
}
}
}
})
</script>
</body>
</html>
总结:
监视属性watch:
- 当被监视的属性变化时,回调函数自动调用,进行相关操作(data中的变量属性、计算属性都可被监听);
- immediate:true属性作用 (刷新时)初始化时让handler调用一下
- 监视的属性必须存在,才能进行监视,若不存在也不会报错!!!
- 监视有两种写法:
- 创建Vue时传入watch配置
- 通过
vm.$watch
监视
动态变量监视:若要监视的属性不确定时或监视属性需要动态切换时,此写法应该可以将要监视的属性以变量形式传入
vm.$watch('isHot',{
immediate:true,
handler(newValue,oldValue){
console.log('isHot被修改了',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">
<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>
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
isHot:true,
numbers:{
a:1,
b:1,
}
},
watch:{
//监视多级结构中所有属性的变化
numbers:{
deep:true,
handler(newValue,oldValue){
console.log(newValue,oldValue,'numbers改变了'); // {__ob__: Observer} {__ob__: Observer} 'numbers改变了'
}
}
//监视多级结构中某个属性的变化
'numbers.a':{
handler(newValue,oldValue){
console.log(newValue,oldValue,'a被改变了'); // 2 1 'a被改变了'
}
}
}
})
</script>
</body>
</html>
总结:
-
深度监视:
-
Vue中的watch默认不监测对象内部值的改变(一层)
-
在watch中配置deep:true可以监测对象内部值的改变(多层)
-
-
备注:
-
Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
-
使用watch时根据监视数据的具体结构,决定是否采用深度监视
-
监视属性简写
如果监视属性除了handler没有其他配置项的话,可以进行简写。
<script type="text/javascript">
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:{
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
},
//简写
isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
}
}
})
//正常写法
vm.$watch('isHot',{
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
//简写
vm.$watch('isHot',function(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
})
</script>
总结:
-
computed和watch之间的区别:
-
computed能完成的功能,watch都可以完成
-
watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
-
-
两个重要的小原则:
-
所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象
-
所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。
-
计算属性与监听属性区别总结
从上面的特点来说,我们可以得出结论:
1).计算属性的应用场景是计算的内容需要依赖多个属性的情况
侦听器的应用场景是计算的内容依赖一个属性的情况
2).计算属性缓存结果时每次都会重新创建变量
而侦听器是直接计算,不会创建变量保存结果
也就意味着,数据如果会反复的发生变化,计算很多次的情况下,计算属性的开销将会更大,也就意味着这种情况不适合使用计算属性,适合使用侦听器
那么,如果一个数据反复会被使用,但是它计算依赖的内容很少发生变化的情况下,计算属性会缓存结果,就更加适合这种情况。3).watch可以进行异步操作(开启定时任务),computed因存在return则无法进行异步操作(开启定时任务)。
4).computed的结果是通过return返回的,而watch不需要return。
5).watch中的参数可以得到侦听属性改变的最新结果,而computed函数没有这种参数。补充:
watch只会监听数据的值是否发生改变,而不会监听地址的变化,如果需要监听引用类型的数据变化,需要深度监听:obj:{handler(newVal){},deep:true}------用handler+deep的方式进行深度监听。
在特殊的情况下(更改数组中的数据时,数组已经更改,但是视图没有更新),watch无法监听数组的变化,更改数组必须要用splice()或者$set。
结论:
我们在计算开销比较大(计算次数多或者异步处理)的时候,会使用侦听器watch来得到计算结果。
而其他情况建议使用计算属性computed,因为缓存节省多次计算的性能在大多数情况下,你应该优先考虑使用计算属性,因为它们更加简洁、易于维护,并且与 Vue 的响应式系统更紧密集成。只有在计算属性不适用时,才考虑使用
watch
监听器
计算属性实现 模糊搜索+排序 小案例
<!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>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<div id="root">
<h1>人员列表</h1>
<input type="text" v-model="keyWord">
<button @click="sortType = 2">升序</button>
<button @click="sortType = 1">降序</button>
<button @click="sortType = 0">原顺序</button>
<ul>
<li v-for="(item,index) in filPersons" :key="item.id">
{{item.id}}--{{item.name}}--{{item.age}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
let vm = new Vue({
el: "#root",
data: {
keyWord: "",
sortType: 0,
persons: [
{ id: '001', name: '马冬梅', age: '18' },
{ id: '002', name: '周冬雨', age: '15' },
{ id: '003', name: '周杰伦', age: '13' },
{ id: '004', name: '温兆伦', age: '14' },
],
},
computed: {
filPersons() {
const arr = this.persons.filter((item) =>
item.name.indexOf(this.keyWord) != -1
)
if (!!this.sortType) {
arr.sort((a, b) =>
this.sortType == 1 ? b.age - a.age : a.age - b.age
)
}
return arr;
}
}
})
</script>
</body>
</html>