计算属性

计算属性和监听属性免费看

本节我们学习计算属性和监听属性,包括计算属性缓存vs方法、计算属性的Setter等。

2020-12-20侠课岛    基础入门       

前端/前端/Vue3入门基础 11     0     2186

模板内的表达式计算是非常便利的,但是如果涉及到非常复杂的计算方式,一个结算结果如果依赖很多个变量,就会变得难以维护了,所以计算属性就此应运而生了。

使用计算属性(computed)有一个好处在于它有一个缓存机制,因此它不需要每次都重新计算。当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的 DOM 部分也会同步自动更新。在处理一些复杂逻辑时计算属性是很有用的。

计算属性

Vue 中我们可以使用模板语法 {{}} 来展示一些数据,而当在模板中放入太多的逻辑会让模板过重且难以维护。这种情况下,Vue 给我们提供了一个特别好的解决方法,就是使用计算属性。我们可以将一些需要计算的过程写入到一个计算属性中去,然后让它动态的计算就可以了。

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如有一个嵌套数组对象:

Vue.createApp({
  data() {
    return {
      author: {
        name: '金庸',
        books: [
          '射雕英雄传',
          '雪山飞狐',
          '神雕侠侣'
        ]
      }
    }
  }
})

我们想根据 author 是否已经有一些书来显示不同的消息:

<div id="computed-basics">
  <p>出版过书籍吗?</p>
  <span>{{ author.books.length > 0 ? '是' : '否' }}</span>
</div>

此时,模板不再是简单的和声明性的。必须先看一下它,然后才能意识到它执行的计算取决于 author.books。如果要在模板中多次包含此计算,则问题会变得更糟。

所以,对于任何包含响应式数据的复杂逻辑,我们都应该使用计算属性。

基本例子

下面这个例子判断作者是否成功出版过书籍:

<div id="computed-basics">
    <p>出版过书籍吗?</p>
    <span>{{ publishedBooksMessage }}</span>
</div>
Vue.createApp({
  data() {
    return {
      author: {
        name: '金庸',
        books: [
          '射雕英雄传',
          '雪山飞狐',
          '神雕侠侣'
        ]
      }
    }
  },
  computed: {
    // 计算属性的 getter
    publishedBooksMessage() {
      // this指向vm实例
      return this.author.books.length > 0 ? '是' : '否'
    }
  }
}).mount('#computed-basics')

我们可以看一下浏览器中的效果:

上述代码中声明了一个计算属性 publishedBooksMessage。尝试修改 databooks 数组的值,将可以看到 publishedBooksMessage 如何相应地更改。

我们可以像普通属性一样将数据绑定到模板中的计算属性。Vue 知道 vm.publishedBookMessage 依赖于 vm.author.books,因此当 vm.author.books 发生改变时,所有依赖 vm.publishedBookMessage 绑定也会更新。而且最妙的是我们已经声明的方式创建了这个依赖关系:计算属性的 getter 函数没有副作用,这使得更易于测试和理解。

计算属性缓存 vs 方法

我们可以通过在表达式中调用方法来达到同样的效果:

<p>{{ calculateBooksMessage() }}</p>
// 在组件中
methods: {
  calculateBooksMessage() {
    return this.author.books.length > 0 ? 'Yes' : 'No'
  }
}

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的反应依赖关系缓存的。计算属性只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 author.books 还没有发生改变,多次访问 publishedBookMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

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

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 list,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 list。如果没有缓存,我们将不可避免的多次执行 list 的 getter!如果不希望有缓存,可以使用 method 来替代。

计算属性的Setter

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter

// ...
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstNamevm.lastName 也会相应地被更新。

监听属性

监听属性(watch)可以监听一个函数或者是一个变量,通过 watch 来响应数据的变化。虽然大多数情况计算属性都可以满足需要,但有时还是需要使用侦听器。当需要在数据发生变化时执行异步操作或者开销较大的操作时,就需要自定义监听器。

示例:

例如我们想实现一个计数器,我们可以通过 watch 来响应数据的变化:

<div id="increase">
    <p>计算器:{{num}}</p>
    <button @click="num++">点我加一</button>
</div> 
const app = Vue.createApp({
  data() {
    return {
      num: 1
    }
  }
}).mount('#increase')

// 监听器
app.$watch('num', function(navl, oval){
  alert("计数器的值从 " + oval + "变为" + navl);
});

我们在浏览器中看一下演示效果:

watch 这个对象里面是一个函数,函数的名称是 data 中的属性名称,也就是 num。并且 watch 中的函数不需要调用。

当属性 num 发生改变,就会触发 watch 函数(num 所对应的函数),每个函数都会接受两个值,一个是新值navl,一个是旧值oval

例如当我们第一次点击按钮时,会弹出一个弹出层,告诉我们“计数器的值从 1 变为 2”,然后我们点击弹出层的 “确认” 按钮,计数器显示的值成功变为了 2。

本教程图文或视频等内容版权归侠课岛所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、转贴或以其他方式复制发布或发表。

评价

11

本课评分:
  •     非常好
难易程度:
  •     适中的

内容目录


本文索引


|
教程
粉丝
主页

签到有礼

已签到2天,连续签到7天即可领取7天全站VIP

  • 1
    +2 金币
  • 2
    +3 金币
  • 3
    +5 金币
  • 6
    +7 金币
  • 5
    +6 金币
  • 4
    暖心福利
    自选分类VIP ×1天
  • 7
    惊喜大礼

    自选分类VIP ×3天 +20金币
  • 持续签到 +8 金币

金币可以用来做什么?