参考一:

在 Vue 中,computed 的属性可以被视为是 data 一样,可以读取和设值,因此在 computed 中可以分成 getter(读取) 和 setter(设值),一般情况下是没有 setter 的,computed 预设只有 getter ,也就是只能读取,不能改变设值。

vue.js计算属性默认只有 getter,因为是默认值所以我们也常常省略不写,如下代码:

<div id="demo">{{ fullName }}</div>

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

其实computed里的代码完整的写法应该是:

 computed: {
    fullName: {
      get(){
         return this.firstName + ' ' + this.lastName
      }
    }
  }

计算属性getter的触发时间

<template>
    <div id="demo">
         <p> {{ fullName }} </p>
         <input type="text" v-model="firstName">
         <input type="text" v-model="lastName">
    </div>
</template>

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'zhang',
    lastName: 'san'
  },
  computed: {
    fullName: function () {
      console.log('computed getter...')
      return this.firstName + ' ' + this.lastName
    }
  },
  updated () {
     console.log('updated')
  }
})

如果我们改变上边代码里的2个输入框的值firstName或者lastName,都会触发computed以及updated (),也就是说会执行: console.log('computed getter...')和console.log('updated') (用来验证是不是执行了,没有其他意思)

需要注意的是,不是说我们更改了getter里使用的变量,就会触发computed的更新,前提是computed里的值必须要在模板里使用才行。怎么理解呢?

如下代码,我们把template里的fullName 注释掉:

<template>
    <div id="demo">
         <!-- <p> {{ fullName }} </p> -->
         <input type="text" v-model="firstName">
         <input type="text" v-model="lastName">
    </div>
</template>

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'zhang',
    lastName: 'san'
  },
  computed: {
    fullName: function () {
      console.log('computed getter...')
      return this.firstName + ' ' + this.lastName
    }
  },
  updated () {
     console.log('updated')
  }
})

就算我们更改了firstName以及lastName都不会触发computed 中的 getter 中的console.log('computed getter...'),而只会触发console.log('updated')

计算属性settter

<template>
    <div id="demo">
         <p> {{ fullName }} </p>
         <input type="text" v-model="fullName">
         <input type="text" v-model="firstName">
         <input type="text" v-model="lastName">
    </div>
</template>

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'zhang',
    lastName: 'san'
  },
  computed: {
    fullName: {
      //getter 方法
        get(){
            console.log('computed getter...')
            return this.firstName + ' ' + this.lastName
        },
   //setter 方法
        set(newValue){
            console.log('computed setter...')
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
            return this.firstName + ' ' + this.lastName
        }
      
    }
  },
  updated () {
     console.log('updated')
  }
})

在template 中,我们可以看到,input 是直接绑 v-model="fullName",如果我们这里直接修改了fullName的值,那么就会触发setter,同时也会触发getter以及updated函数。其执行顺序是setter -> getter -> updated,如下:

console.log('computed setter...')
console.log('computed getter...')
console.log('updated')

这里需要注意的是,并不是触发了setter也就会触发getter,他们两个是相互独立的。我们这里修改了fullName会触发getter是因为setter函数里有改变firstName 和 lastName 值的代码。也就是说我们如果注释掉上边的setter中修改firstName 和lastName的代码后就不会执行getter,如下:

set(newValue){
            console.log('computed setter...')
            // var names = newValue.split(' ')
           //  this.firstName = names[0]
          //  this.lastName = names[names.length - 1]
          return this.firstName + ' ' + this.lastName
        }

会执行,且顺序如下

console.log('computed setter...')
console.log('updated')

参考二:

computed 计算属性

定义:当其依赖的属性的值发生变化的时,计算属性会重新计算。反之则使用缓存中的属性值。

一个完整的计算属性如下:

computed: {
 example: {
   get () {
     return 'example'
   },
   set (newValue) {
     console.log(newValue)
   }
 }
复制代码

基础用法

1.计算属性的getter函数

当其依赖的属性的值发生变化的时,这个计算属性的值也会自动更新。多用于"data,computed"的属性。

<template>
  <div>
    <h4>测试</h4>
    <div>
      <input type="text" v-model="message" />
      <div>{{changeMessage}}</div>
    </div>
  </div>
</template>

<script>
   export default {
    data () {
       return {
         message: 'hello'
       }
     },
    computed: {
       changeMessage: {
        // 计算属性:依赖message变化而变化  依赖没变化就不会重新渲染;
        get () {
           return this.message + 'world'
        },
        set () {
        }
      }
     }
  }
</script>
复制代码

2.计算属性的setter函数

当赋值给计算属性的时候,将调用setter函数。多用于在模板组件中需要修改计算属性自身的值的时候。

<template>
  <div>
    <h4>测试</h4>
    <div>
      {{didi}}
      {{family}}
    </div>
    <div>
      {{didiFamily}}
    </div>
  </div>

</template>

<script>
   export default {
    data () {
       return {
        didi: 'didi',
        family: 'family'
       }
     },
    computed: {
      didiFamily:{
        //getter
        get:function(){
          return this.didi + ' ' + this.family
        },
        //setter
        set:function(newValue){
          // 这里由于该计算属性被赋值,将被调用
          console.log(newValue)
          this.didi = 123
          this.family = 456
        }
      }
    },
    mounted () {
      // 赋值,调用setter函数
      this.didiFamily = 'John Doe'
    }
  }
</script>
复制代码

3.计算属性的缓存

Vue实例中被观察的数据属性发生了改变时才会重新执行getter,但是我们有时候计算属性依赖实时的非观察数据属性,比如下面例子中的Data.now

<template>
  <div>
    <h4>测试</h4>
    <div>
      <input type="text" v-model="message" />
      <div>{{now}}</div>
    </div>
  </div>

</template>

<script>
   export default {
    data () {
       return {
         message: 'hello'
       }
     },
    computed: {
      now:{
        cache: false,
        get:function(){
          return Date.now() + this.message
        }
      }
    },
    mounted () {
      setInterval(() => {
        // 当缓存开关为false的时候,定时器每次打印的时间都是不一样的
        console.log(this.now)
      }, 500)
    }
  }
</script>
复制代码

1.计算属性getter不执行的场景

当包含计算属性的节点被移除并且模板中其他地方没有再引用该属性的时候,那么对应的计算属性的getter函数方法不会执行

代码实例如下

<template>
  <div>
    <h4>测试</h4>
    <div>
      <button @click="toggleShow">Toggle Show Total Price</button>
      <p v-if="showTotal">Total Price = {{totalPrice}}</p>
    </div>
  </div>

</template>

<script>
   export default {
    data () {
       return {
        showTotal: true,
        basePrice: 100
       }
     },
    computed: {
      totalPrice () {
        return this.basePrice + 1
      }
    },
    methods: {
      toggleShow () {
        this.showTotal = !this.showTotal
      }
    }
  }
</script>
复制代码

2.在v-for中使用计算属性,起到类似"过滤器的作用"

<template>
  <div>
    <h4>测试</h4>
    <div>
      <ul>
      	<li v-for="n in evenNumbers">{{n}}</li>
      </ul>
    </div>
  </div>

</template>

<script>
   export default {
    data () {
       return {
        numbers: [ 1, 2, 3, 4, 5 ]
       }
     },
    computed: {
      evenNumbers () {
        return this.numbers.filter(function (number) {
          return number % 2 === 0
        })
      }
    }
  }
</script>

复制代码

3.watch与computed的set函数的比较

vuex 接收 的computed ,用set监测不到变化,必须要用watch才可以生效;(原理:实质没有改变computd的值,只是改变了get的return值 => 组件外的访问)

v-model 改变的computed,用watch监测不到变化,必须要用computed对象中的set函数方法才能监测得到(原理:相当于每次改变了computed自身的值 => 组件内的访问)

参考三:

一、getter 和 setter

首先要明确一点,每一个计算属性都包含一个 getter 函数和 setter 函数。

举个栗子:来实现一个 "显示姓名" 的 小demo 。

<div id="app">
    {{ fullName }}                      // 3、渲染 fullName
</div>

var app = new Vue({
  el: '#app',
  data: {                               // 1、在data中定义 firstName 和 lastName
    firstName: 'Barry',
    lastName: 'Dong'
  },
  computed: {                          // 2、在计算属性中定义 fullName
    fullName: function () {
      return this.firstName + this.lastName
    }
  }
})

现在你可以在页面中看到 "BarryDong" 。

等等,getter 和 setter 呢?你不是说每一个计算属性都包含一个 getter 和 setter 吗?上面这个 demo 怎么没有呢?

这是因为,计算属性会默认使用 getter 函数。也就是说,即使你没有明确写出 getter 函数,计算属性也会默认使用它。

上面的 demo 中的计算属性,可以改写成这样:

computed: {
    fullName: {
      get: function () {             // 这里就明确写出了 getter 函数
        return this.firstName + this.lastName
      }
    }
}

运行结果与上次结果一致。

那么 setter 函数呢?

setter 函数与 getter 函数类似,也是写在计算属性中。而不同之处在于,getter 函数是默认用法,setter 函数不是默认用法。如果你要使用 setter 函数,那么你必须要手动写出 setter 函数。

比如,上面的 demo ,需求变了:我要能显示名字的同时,还能改变名字。(这里我们要求,姓与名之间要用中文逗号分隔,不然不好识别哪个是姓,哪个是名)

<div id="app">
    {{ fullName }} <br>
</div>

var app = new Vue({
  el: '#app',
  data: {
    firstName: 'Barry',
    lastName: 'Dong'
  },
  computed: {
    fullName: {
      get: function () {
        return this.firstName + this.lastName
      },
      set: function (newName) {        // 我们加上了 setter 函数,可以传入新的名字
        var name = newName.split(',')  // 把传入的名字根据逗号,拆分成数组
        this.firstName = name[0]    // 数组的第一个元素为 firstName
        this.lastName = name[1]     // 数组的第二个元素为 lastName
      }
    }
  }
})

现在我们打开控制台,在控制台中改变名字:

访问 Vue 实例的属性的属性,直接使用点运算符即可

那么现在可以看到,页面中渲染出了 "曾小贤" 。

总结:

  • 每一个计算属性都包含一个 getter 函数和 setter 函数;
  • 计算属性会默认使用 getter 函数;
  • 你也可以提供 setter 函数,当修改计算属性的值时,就会触发 setter 函数,执行一些自定义的操作。

二、methods 与 computed

首先要知道,methods 里的方法,与 computed 里的方法,可以起到同样的作用。

举个栗子:做一个 "现在距1970年的时间戳" demo 。

<div id="app">
    方法拿到的时间戳:{{ now() }} <br>
    计算属性拿到的时间戳:{{ thisTime }}
</div>

var app = new Vue({
  el: '#app',
  data: {
    
  },
  methods: {               // 你看下面 computed 中的方法,是不是类似的?
    now: function () {
      return Date.now()
    }
  },
  computed: {
    thisTime: function () {
      return Date.now()
    }
  }
})

可以看到,两种方法都拿到了时间戳。

那么细心的同学会发现,上面代码中:

<div id="app">
    方法拿到的时间戳:{{ now() }} <br>    // now 后面有括号
    计算属性拿到的时间戳:{{ thisTime }}  // thisTime 后面没有括号
</div>

这是为啥呢?

因为,now 是写在 methods 中的,所以要调用。而 thisTime 是写在 计算属性 中的,既然是属性,那自然就不用加括号了。

请牢记这一点。


三、计算属性的缓存

这里要结合 methods 来对比学习。

methods:只要页面重新渲染,methods 中的方法就会重新执行;不渲染,就不执行。

如:

<div id="app">
    {{ text }}
</div>

var app = new Vue({
  el: '#app',
  data: {
    text: '星星点灯',          // text 在页面中渲染
    message: '照亮我的前程'    // message 未在页面中渲染
  },
  computed: {
    ...
  },
  methods: {
    ...
  }
})

如果通过 app.text 改变了 text 的值,那么页面就会重新渲染出 text 的值,methods 中的方法也会重新执行。而如果改变的是 message ,因为 message 未在页面中渲染,那么页面就不会重新渲染 message 的值,methods 中的方法不会重新执行。

computed:不管页面是否渲染,只要计算属性依赖的数据未发生改变,那么计算属性就不会发生变化,因为计算属性是基于它的缓存的。只有当计算属性依赖的数据发生变化时,计算属性才会重新取值。

如:

<div id="app">
    {{ abc }}
</div>

var app = new Vue({
  el: '#app',
  data: {
    text: '星星点灯',
    message: '照亮我的前程',
    dongdong: '哼哼哈嘿'
  },
  computed: {
    abc: function () {
      return this.text + this.message    // 计算属性依赖了 Vue 实例中的 text 和 message
    }
  },
  methods: {
    
  }
})

如果我将 Vue 实例中的 text 属性更改:

那么计算属性就会重新取值,重新渲染:

页面重新渲染

而如果我更改实例中的 dongdong 属性,因为计算属性没有依赖它,所以计算属性不会变:

页面仍然显示:

 

那我们要在什么时候使用计算属性呢?

那就取决于你是否需要使用缓存了!如果你要遍历一个很大的数组,或者要进行大量的运算,那么你就可以使用计算属性。

 

补充一点:

计算属性不仅可以依赖当前 Vue 实例的数据,还可以依赖其他 Vue 实例的数据。

<div id="app">
    {{ text }} <br>
    {{ reverseText }}
</div>

var app2 = new Vue({
  el: '#app2',
  data: {
    text: '你自己却不知道'
  }
})

var app = new Vue({
  el: '#app',
  data: {
    text: '我想说其实你很好'
  },
  computed: {
    reverseText: function() {
      return this.text.split('').reverse().join('') + ',' + app2.text    // 依赖 app2 中的 text
    }
  }
})

如果 app2 中的 text 改变,那么计算属性也会随之改变。

Logo

前往低代码交流专区

更多推荐