Vue基础篇--计算属性(computed) 和侦听器(watcher)

计算属性

使用示例

计算属性:类似于使用getter函数获得的一个属性值,使用属性访问的方式从一个function中获取属性的结果,并且这个结果可以根据function中响应式数据的变化而自动变化。它的优点有:

  • 用一个变量替代去替代一个复杂的表达式
  • 可以将表达式的计算结果缓存供下次使用

举个例子说明,data中定义了一个message变量,现在我们需要将这个message中的字符全部颠倒后在页面中展示,可以使用下面的几种方法

<div id="example">
  <p> 原 message {{ message }}</p>
  <p> 方法一:{{ message.split('').reverse().join('') }} </p>
  <p> 方法二:{{ reversedMsg() }} </p>
  <p> 方法三:{{ reversedMessage }} </p>
</div>

<script>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  methods:{
    reversedMsg(){
      return this.message.split('').reverse().join('')
    }
  }
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      return this.message.split('').reverse().join('')
    }
  }
})
</script>

第三种使用方式为计算属性,它的使用方式和data种定义的message变量的使用方式相同,使用this.reversedMessage便可以访问。它的值会自动根据reversedMessage函数计算得到,且会根据函数内部的响应式数据this.message的改变而自动改变。
比较它与前两种方式的优缺点:
方法1:直接使用模板语法

  • 这样的书写方式复杂,不利于阅读理解,代码可读性差
  • 如果多个地方都需要展示这个结果,这个表达式要写多遍
  • 如果多个地方使用该值,也会执行多遍计算

方法2:使用一个函数返回值表示

  • 如果多个地方使用该值,这个函数会执行多遍

方法3:计算属性

  • 因为内部有缓存机制,只进行一次计算,后面直接使用上次的结果。

计算属性缓存

计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。所以这个例子中只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

由于属性的更新只和内部响应式依赖相关,所以下面该属性值,无论在哪个时刻调用,结果都是不会改变的。如果希望它改变,使用上面第二种函数的方式

computed: {
  now: function () {
    return Date.now()
  }
}

计算属性的setter

计算属性可以获取值,也可以重新给他赋值,这就需要定义setter函数

data:{
  firstName: 'Foo',
  lastName: 'Bar',
}
computed: {
  fullName: {
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter, 执行this.fullName = "A B"表达式时,set函数触发,newValue形参接受"A B"参数
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[-1]
    }
  }
}

侦听器watcher

简单来说,可以设置监听一个表达式或函数的结果变化。变化时执行回调函数,回调函数得到的参数为变化前后的新值和旧值,表达式支持单个变量和一个简单的属性访问路径,需要监听更复杂的表达式,需要使用函数取代。
常见的几种用法

var vm = new Vue({
  el:"",
  methods:{},
  data: { msg: "", msg2:""},
  watch:{
    "msg": function(newVal, oldVal){},            // 当data中msg 发生改变时,触发执行该函数。
    "msg2":function(newVal, oldVal){},
    "$route.path": function(newVal, oldVal){}    // 当路由变量发生改变时候,触发该函数
    function(){
      return this.msg + this.msg2
    }
  }
})
// 外部定义
var unwatch = vm.$watch("a.b.c", function(new, old){
  // 监听回调
})
// 调用 unwatch() 取消监听

$watch函数会得到一个unwacth函数对象,执行该函数,将会取消这个监听器。

被监听的变量如果是一个引用类型,例如对象或者数组,那个这个引用类型内部的数据更改并不会触发watch 回调,只有监听的对象发生了替换,才会视作一个更改操作,从而触发回调函数。为了可以发现内部值的变化,需要增加一个deep:true的选项,而immediate参数可以阻止该监听器第一次回调时就取消该监听。

var unwatch = vm.$watch("a.b.c", function(new, old){},{’deep‘: true, 'immediate':true})

监听器的回调函数不能使用箭头函数语法定义,因为箭头函数会自动绑定父级的this指针,会造成原本的this指针被覆盖。

监听器和计算属性的选择

使用官网的例子比较两者的使用:功能 展示fullName,且fullName 在firstName和lastName任意一个更新时进行更新

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

第一种:使用监听器,监听 firstName 和 lastName,两个变量改变时都触发更新

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

第二种:使用计算属性,fullName会始终依赖于 firstName 和 lastName 进行同步更新

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

总结:

  • 在大多数场景下都更加适合使用计算属性解决需求,因为计算属性内部会自动监听依赖的响应式变量,也实现了侦听器的效果,更偏向于可以自动获取某个结果需求。
  • 监听器主要用在触发一个异步操作,计算时间过长的操作。更偏向于触发某个操作的考虑而不是获取结果
posted @ 2022-06-06 23:08  没有想象力  阅读(338)  评论(0编辑  收藏  举报