## 计算属性

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

Vue.createApp({data() {return {author: {name: 'John Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']}}}
})

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

<div id="computed-basics"><p>Has published books:</p><span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
</div>

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

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

基本例子

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="computed-basics"><p>Has published books:</p><span>{{ publishedBooksMessage }}</span>
</div>
</body>
<script>Vue.createApp({data() {return {author: {name: 'John Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']}}},computed: {// 计算属性的 getterpublishedBooksMessage() {// `this` 指向 vm 实例return this.author.books.length > 0 ? 'Yes' : 'No'}}}).mount('#computed-basics');
</script>
</html>

结果:

这里声明了一个计算属性 publishedBooksMessage。

尝试更改应用程序 data 中 books 数组的值,你将看到 publishedBooksMessage 如何相应地更改。

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

计算属性缓存 vs 方法

你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="computed-basics"><p>Has published books:</p><span>{{ calculateBooksMessage() }}</span>
</div>
</body>
<script>Vue.createApp({data() {return {author: {name: 'John Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']}}},methods: {calculateBooksMessage() {return this.author.books.length > 0 ? 'Yes' : 'No'}}}).mount('#computed-basics');
</script>
</html>

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

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="computed-basics"><p>Has published books:</p><span>{{ now }}</span>
</div>
</body>
<script>Vue.createApp({data() {return {author: {name: 'John Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']}}},computed: {//Date.now () 不是响应式依赖now() {return Date.now()}}}).mount('#computed-basics');
</script>
</html>

结果:

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

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

计算属性的 Setter

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

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="computed-basics"><p>Has published books:</p><span>{{ fullName }}</span>
</div>
</body>
<script>const app = Vue.createApp({data() {return {author: {firstName: 'John',lastName: ' Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']}}},computed: {fullName: {// getterget() {return this.author.firstName + ' ' + this.author.lastName;},// setterset(newValue) {const names = newValue.split(' ');;this.author.firstName = names[0];this.author.lastName = names[1];}}}})const vm = app.mount('#computed-basics');
</script>
</html>

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

侦听器

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="watch-example"><p>Ask a yes/no question:<input v-model="question" /></p><p>{{ answer }}</p><img src = "imageUrl">
</div>
</body>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>const watchExampleVM = Vue.createApp({data() {return {question: '',answer: 'Questions usually contain a question mark. ;-)',imageUrl: 'https://yesno.wtf/assets/yes/9-6403270cf95723ae4664274db51f1fd4.gif'}},watch: {// whenever question changes, this function will runquestion(newQuestion, oldQuestion) {if (newQuestion.indexOf('?') > -1) {this.getAnswer()}}},methods: {getAnswer() {this.answer = 'Thinking...'axios.get('https://yesno.wtf/api').then(response => {this.answer = response.data.answer}).catch(error => {this.answer = 'Error! Could not reach the API. ' + error})}}}).mount('#watch-example')
</script>
</html>

在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

除了 watch 选项之外,你还可以使用命令式的 vm.$watch API。

计算属性 vs 侦听器

Vue 提供了一种更通用的方式来观察和响应当前活动的实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。细想一下这个例子:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="demo">{{ fullName }}</div>
</body>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>const vm = Vue.createApp({data() {return {firstName: 'Foo',lastName: 'Bar',fullName: 'Foo Bar'}},watch: {firstName(val) {this.fullName = val + ' ' + this.lastName},lastName(val) {this.fullName = this.firstName + ' ' + val}}}).mount('#demo')
</script>
</html>

上面代码是命令式且重复的。将它与计算属性的版本进行比较:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://unpkg.com/vue@next"></script><!--导入lodash库--><script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
</head>
<body>
<div id="demo">{{ fullName }}</div>
</body>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>const vm = Vue.createApp({data() {return {firstName: 'Foo',lastName: 'Bar'}},computed: {fullName() {return this.firstName + ' ' + this.lastName}}}).mount('#demo')
</script>
</html>

好很多了,不是吗?

VUE自学日志05-计算属性和侦听器相关推荐

  1. Vue.js 计算属性和侦听器

    计算属性和侦听器 计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护.例如: <div id="example" ...

  2. (第二篇)Vue计算属性、侦听器、过滤器

    1.计算属性和侦听器 <!DOCTYPE html> <html lang="en"> <head><meta charset=" ...

  3. 5.Vue 计算属性和侦听器

    Hello,我是 Alex 007,一个热爱计算机编程和硬件设计的小白,为啥是007呢?因为叫 Alex 的人太多了,再加上每天007的生活,Alex 007就诞生了. 5.Vue 计算属性和侦听器 ...

  4. vue修改计算属性的值_Vue语法高级之计算属性和侦听器

    计算属性和侦听器都可以监听到data区数据的变化,当数据变化时可以触发方法的调用,从而在方法内部可以进行相应的逻辑处理. 计算属性的语法格式是:computed: {} 侦听器的语法格式是:watch ...

  5. VUE基本使用---安装、开始使用介绍、Vue实例、模板语法、计算属性和侦听器、class与style绑定

    原文在我的博客:https://www.liboer.top/articles/detail/vue-BasedUse/ 文章目录 VUE.js 基础 安装 CDN 下载 安装 命令行工具(CLI脚手 ...

  6. Vue:实例演示,v-if,v-for,v-model,v-bind,v-on,计算属性和侦听器属性

    Vue:实例演示,v-if,v-for,v-model,v-bind,v-on,计算属性和侦听器属性 一.实例演示,v-if,v-for,v-model,v-bind,v-on 方法 含义 v-bin ...

  7. 光脚丫思考Vue3与实战:第05章 计算属性和侦听器 第02节 侦听器

    下面是本文的屏幕录像的在线视频: 温馨提示: 1.视频下载:线上视频被压缩处理,可以下载高清版本: 链接:https://pan.baidu.com/s/1qUekWio3fpWToT9PiECpEg ...

  8. Vue 计算属性与侦听器

    这一节我们一起学习 vue 中的计算属性(computed properties)和侦听器(watch). 在之前,我们学习过 vue 表达式插值: <div id="example& ...

  9. vue修改计算属性的值_「Vue学习记录五」计算属性和侦听器

    1: 计算属性: (内置缓存机制) 当更改age的时候, fullName 函数不执行: 当更改fristName的时候, fullName 函数才执行 <div id = "app& ...

最新文章

  1. SpringBoot复习:5(配置绑定)
  2. 关于大脑未必是破解智能和意识之谜的钥匙探讨
  3. iphone录屏怎么录声音_ev录屏怎么录制声音 ev录屏声音设置教程
  4. python图表可视化工具_比Excel制图更强大,Python可视化工具Altair入门教程
  5. 系统制成docker镜像_docker 制作自己的镜像
  6. .NET方法演化史 从Delegate到Lambda再到LINQ
  7. 持续交付 devops_使用DevOps开始加速软件交付
  8. speedtest命令行linux,Linux或者Mac下命令行speedtest测试网络速度
  9. makefile中 = ,:=,+=有怎么区别?
  10. Debian — command not found
  11. php mysql修改表单数据_表单修改数据
  12. rk3568 android 11 更换系统签名
  13. python判断身份证号码是否合法_怎样使用 Python 判断身份证号码是否正确-阿里云开发者社区...
  14. java解析project mpp文件_Java解析Project mpp文件
  15. 内蒙古自治区鄂尔多斯市谷歌高清卫星地图下载
  16. 基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]
  17. Microsoft Surface 平板电脑
  18. 校验国内外的座机和手机号码
  19. zsh补全中compinit full initialization问题
  20. 递归皮质网络RCN简单理解

热门文章

  1. django模型的元数据Meta
  2. C# MD5,hmacSHA1
  3. C++11/14学习(二)类型推导
  4. 1-14字串的连接最长路径查找
  5. cf Round 613
  6. 【00】why集搜客网络爬虫?
  7. vsftpd安装、多用户配置
  8. 原创电子书:C#难点逐个击破
  9. 有段时间没更新了。。。放上我在做的东东的截图
  10. 常用的优化方法-梯度下降、牛顿法、坐标下降法