浅谈Vue2选项--computed

113 阅读3分钟

计算属性的概念

  • 本质:函数 (必须有返回值)| 对象(带getter和setter)

  • 解决问题: 模板中过多的逻辑会让模板过重且难以维护,计算属性就是处理这种复杂逻辑的

  • 原理: 当依赖的数据发生变化时,计算属性的值会自动更新,与之相关的DOM部分也同步更新

  • 理解: 通过一系列运算之后,最终得到一个属性值

  • 特点:

    1. 数据可以进行逻辑处理,减少模板中计算逻辑
    2. 对依赖的数据进行监视
    3. 依赖响应式数据
  • 运用:

    1. 定义时要被定义为方法
    2. 使用计算属性时,当普通属性使用即可
    3. 在模板结构或 methods方法使用

函数类型

 <h1>{{fullName}}</h1>
 data(){
   return { 
     firstName: 'Lebron',
     lastName: 'James'
   }
 },
 ​
 computed: {
   fullName(){
     return `${this.firstName}·${this.lastName}`
   }
 }

1667061735540.png

  • Vue 知道 fullName 依赖于 firstNamelastName,当两者之一发生改变时,所有依赖 fullName 的绑定也会更新

注意:计算属性的值不能在组件的 propsdata 中定义

计算属性可以使用箭头函数吗?this 指向谁?

  • this 指向 undefined
 computed: {
   fullName:()=>{ console.log(this) } // 输出undefined     
 }
  • 可以通过函数的内置参数访问 this
 computed: {
   fullName:(vm)=>`${vm.firstName}·${vm.lastName}`  // vm就是当前组件实例    
 }

对象类型

  • 对象类型的计算属性由两部分组成
  • get()set(), 分别用来获取计算属性设置计算属性

getter

  • 根据其它依赖属性动态计算当前属性值 (获取计算属性)
  • 默认情况下只有 getter
 <h1>{{fullName}}</h1>
 data(){
   return { 
     firstName: 'Lebron',
     lastName: 'James'
   }
 },
 ​
 computed: {
   fullName:{
     get(){
       return `${this.firstName}·${this.lastName}`
     }
   }
 }

setter

  • setter 需要自行添加
  • 不是直接修改计算属性,而是修改它的依赖数据
 computed: {
   fullName:{
     get(){
       return `${this.firstName}·${this.lastName}`
     },
     set(newVal){
       console.log(newVal); // 新值是当前修改后的值
     }
   }    
 }

1667063422618.png

为什么模板中的值没发生变化?

  • 因为 fullName 依赖的数据并没发生变化
  • 只有修改其依赖的数据,计算属性才会动态更改
 computed: {
   fullName:{
     get(){
       return `${this.firstName}·${this.lastName}`
     },
     set(newVal){
       const newName = newVal.split('·')
       this.firstName = newName[0]
       this.lastName = newName[1]
     }
   }    
 }

1667063616565.png

计算属性缓存

  • 将同一函数定义为一个 methods 和一个 computed,两种方式的结果是完全不同

  • 计算属性与方法的差异: 计算属性可以基于响应式依赖进行缓存,而 methods 不会缓存

    • 只有相关响应式依赖发生改变, computed 才会重新求值

示例:

  • 使用 methods 进行更改数据,可以看到 getFullName 方法会被调用 4 次
 <h1>{{getFullName()}}</h1>
 <h1>{{getFullName()}}</h1>
 <h1>{{getFullName()}}</h1>
 <h1>{{getFullName()}}</h1>
 methods:{
   getFullName(){
     console.log('执行');
     return `${this.firstName}·${this.lastName}`
   }
 }

1667064102073.png

  • 使用计算属性进行改写数据,方法只调用一次
 <h1>{{fullName}}</h1>
 <h1>{{fullName}}</h1>
 <h1>{{fullName}}</h1>
 <h1>{{fullName}}</h1>
 computed: {
   fullName(){
     console.log('执行computed');
     return `${this.firstName}·${this.lastName}`
   }
 },

1667064287222.png

对比侦听器

1667064381555.png

从上面两张图可以看出 computedwatch 的差异

  1. 监听值以及变化

watch: 侦听的是属性值, 一旦属性值发生变化,都会触发对应回调来执行响应操作,开销较大

computed: 监听的是依赖值,依赖值不变时直接读取缓存复用,变化时才会重新计算

  1. 是否异步

watch:可以执行异步操作,例如发送网络请求

computed: 不能执行异步任务,必须同步执行

也就是说,watch 可以监听计算属性

总结:

  • 计算属性可以实现的,侦听器也可以,反之不成立
  • 能用计算属性尽量使用

问题:计算属性如果是函数,可以传参数吗?

  • 可以!通过闭包的方式,计算属性也可以传参数
 <h1>{{fullName(1,2)}}</h1>
 computed: {
   fullName(){
     return function(a,b){
       console.log(a,b);
       return `${this.firstName}·${this.lastName}`
     }
   }
 },

1667065058017.png

注意: 这样就会失去计算属性的缓存功能