对于刚开始学习Vue的开发者来说,十分容易混淆Vue中计算属性、方法和侦听属性,希望通过本文的介绍,您能了解并分辨这三者的区别。

熟悉 Vue 的同学都知道:在Vue框架中,计算属性(computed)、方法(methods)和侦听属性(watchers)充当着非常重要的角色,它们既可以用来实现相同的功能,彼此之间又存在一些不同之处。三者都有适合自己的场景,我们要想在合适的场景下灵活运用它们,必须对它们有全面的了解。

方法(methods)

正如他的名字一样,它们是挂载在对象上的函数,通常是Vue实例本身或Vue组件。

您可以使用methods对DOM中发生的事件做出反应,也可以从组件中的其他位置调用它们,例如,从计算属性(computed)或侦听(watchers)中调用。

Methods 主要用于对常用功能进行分组,包括处理表单提交,以及构建可重用功能时,例如发出Ajax请求。

在methods对象内部的Vue实例中创建方法如下:

new Vue({
  el: "#app",
  methods: {
    handleSubmit() {}
  }
})

当需要在模板中使用methods时:

<div id="app">
  <button @click="handleSubmit">
    Submit
  </button>
</div>

我们使用v-on指令将事件处理程序附加到我们的DOM元素,DOM元素也可以缩写为\@符号。

以代码中的handleSubmit事件为例,每次单击按钮时都会调用该方法。

对于要传递方法体中需要的参数化的实例,可以执行以下操作:

<div id="app">
  <button @click="handleSubmit(event)">
    Submit
  </button>
</div>

这里我们传递一个事件对象,例如,它允许我们在表单提交的情况下阻止浏览器的默认操作。

但是,当我们使用指令来附加事件时,我们可以使用修饰符来更优雅地实现相同的操作: \@click.stop="handleSubmit"

现在让我们看一个使用methods过滤数组中数据列表的示例。

在代码示例中,我们想要渲染数据列表和搜索框。每当用户在搜索框中输入值时,呈现的数据都会发生变化。模板看起来像这样:

<div id="app">
  <h2>Language Search</h2>
  <div class="form-group">
    <input
      type="text"
      v-model="input"
      @keyup="handleSearch"
      placeholder="Enter language"
      class="form-control"
    />
  </div>

  <ul v-for="(item, index) in languages" class="list-group">
    <li class="list-group-item" :key="item">{{ item }}</li>
  </ul>
</div>

我们引用了一个handleSearch方法,当用户在搜索字段中输入内容时都会调用该方法。我们需要创建methods和数据:

new Vue({
  el: '#app',
  data() {
    return {
      input: '',
      languages: []
    }
  },
  methods: {
    handleSearch() {
      this.languages = [
        'JavaScript',
        'Ruby',
        'Scala',
        'Python',
        'Java',
        'Kotlin',
        'Elixir'

      ].filter(item => item.toLowerCase().includes(this.input.toLowerCase()))
    }
  },
  created() { this.handleSearch() }
})

该handleSearch方法使用输入字段的值来更新列出的项目。需要注意的是,在methods对象中,不需要引用该方法(正如您在React中所做的那样):this.handleSearch

计算属性(Computed)

计算属性看起来像一个方法,但事实却不同。在Vue中,我们使用data来跟踪对特定属性的更改,得到一定的反应。计算属性允许我们定义一个与数据使用相同方式的属性,但也可以有一些基于其依赖关系的自定义逻辑。

虽然上面示例中的“搜索”代码会正常运行,但更优雅的解决方案是使用计算属性。计算属性对于从现有数据源提取组合新数据时非常方便,它们对methods的一大优势是:输出将被缓存。这也意味着如果页面上独立于计算属性的某些内容发生更改并且重新绘制UI时,将返回缓存的结果,并不会重新计算Computed,这样做将大大简化计算步骤,提升处理性能。

计算属性使我们能够使用可用的数据动态进行计算。假设我们有一个性能开销较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算,并且我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!

如下,模板看起来几乎与methods中相同,不同点是我们将指令传递给一个计算属性():v-forfilteredList

<div id="app">
  <h2>Language Search</h2>

  <div class="form-group">
    <input
      type="text"
      v-model="input"
      placeholder="Enter language"
      class="form-control"
    />
  </div>

  <ul v-for="(item, index) in filteredList" class="list-group">
    <li class="list-group-item" :key="item">{{ item }}</li>
  </ul>
</div>

在脚本中,我们声明data属性中的语言(以前这是一个空数组),而不是一个方法,我们将我们的逻辑移动到一个计算属性:

new Vue({
  el: "#app",
  data() {
    return {
      input: '',
      languages: [
        "JavaScript",
        "Ruby",
        "Scala",
        "Python",
        "Java",
        "Kotlin",
        "Elixir"
      ]
    }
  },
  computed: {
    filteredList() {
      return this.languages.filter((item) => {
        return item.toLowerCase().includes(this.input.toLowerCase())
      })
    }
  }
})

该filteredList计算的属性将包含输入字段值项的数组。在第一次渲染时(当输入字段为空时),将渲染整个数组。当用户在字段中输入值时,filteredList将返回一个包含在字段中输入的值的数组。

使用计算属性时,您要计算的数据必须可用,否则会导致应用程序出错。

计算属性创建了一个新filteredList属性,这就是我们可以在模板中引用它的原因。filteredList每次依赖关系时的更改值。这里容易发生变化的依赖是值的input。

最后,请注意计算属性允许我们创建一个变量以在我们的模板中使用,该模板是从一个或多个数据属性构建的。

举例:从用户的名字和姓氏生成fullName:

computed: {
  fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

在下面的场景,但不限于以下场景中,都可以使用Vue的计算属性:

  • 在用户输入时更新大量信息,比如列表的过滤
  • 从Vuex Store中收集相关信息
  • 表单验证
  • 数据可视化的变化取决于用户需要看到什么

侦听属性(watchers)

当一些数据属性发生变化时,我们往往需要执行一些侦听手段,它可以帮助我们监听属性的变化,以便执行对应的操作。如果我们想在每次发生变化时添加一些功能,或者响应某个特定的变化,我们可以侦听一个属性并应用一些逻辑。这意味着watchers的名字必须与我们侦听的属性相同。

当您希望执行操作以响应已发生的更改(例如,对prop或data属性)时,Watchers将会派上用场。正如Vue文档所提到的,当您想要执行异步操作以响应更改的数据时,watchers将非常有用。

在我们的“搜索”示例中,我们可以恢复到最开始的methods示例,并为inputdata属性设置一个侦听程序,并对任何引发input值变化的动作作出反应。

首先,让我们还原模板以使用languages data属性:

<div id="app">
  <h2>Language Search</h2>

  <div class="form-group">
    <input
      type="text"
      v-model="input"
      placeholder="Enter language"
      class="form-control"
    />
  </div>

  <ul v-for="(item, index) in languages" class="list-group">
    <li class="list-group-item" :key="item">{{ item }}</li>
  </ul>
</div>

Vue实例如下所示:

new Vue({
  el: "#app",
  data() {
    return {
      input: '',
      languages: []
    }
  },
  watch: {
    input: {
      handler() {
        this.languages = [
          'JavaScript',
          'Ruby',
          'Scala',
          'Python',
          'Java',
          'Kotlin',
          'Elixir'
        ].filter(item => item.toLowerCase().includes(this.input.toLowerCase()))
      },
      immediate: true
    }
  }
})

在这里,设定侦听属性为一个对象(而不是函数),这样就可以指定一个immediate属性,以便在安装组件后侦听属性可以立即触发。这样做的目的,可使列表具有填充的效果。

结论

古人云:能力越大,责任就越大。

Vue为我们提供了构建优秀应用程序所需的一切,而了解何时使用它们,则是构建用户最喜爱内容的关键。本文介绍了 methods、computed、watcher 三者的用法,但我们的实战项目不可能这么简单,我们在使用 methods、computed、watcher 时,为达到事半功倍的效果,应该合理选择它们最适合的使用场景,就像选择一款最适合你的前端开发工具一样。