这一节咱们一块儿学习 vue
中的计算属性(computed properties
)和侦听器(watch
)。javascript
在以前,咱们学习过 vue
表达式插值:html
<div id="example"> {{ message.split('').reverse().join('') }} </div>
若是在模板中放入太多的逻辑会让模板太重且难以维护。咱们能够把方法写在事件处理函数里面,而且在构造器内部经过 this
调用。
<!-- more -->Html
代码:vue
<h1>{{ this.reversedMessageMethod() }}</h1>
JS
代码:java
methods: { reversedMessageMethod() { return this.message.split('').reverse().join(''); }, },
这里要提醒一下,咱们不能够把事件处理函数写成箭头函数,由于这里的this
须要指向vue
实例。
其实,模板中的处理逻辑是不适合放在事件处理函数里的,即便能够这么作。事件处理函数应该专一于处理事件,咱们应该让它变得纯粹。在 vue
中, 容许咱们自定义过滤器(filters
),可被用于一些常见的文本格式化。git
过滤器能够用在两个地方:双花括号插值和 v-bind
表达式 (后者从 2.1.0+
开始支持)。过滤器应该被添加在 JavaScript
表达式的尾部,由 |
符号指示,咱们看看怎么用:github
<template> <div class='hello'> <h1>{{ message.split('').reverse().join('') }}</h1> <!-- add this --> <h1>{{ message | reverseString }}</h1> </div> </template> <script> export default { name: 'HelloWorld', data() { return { message: 'Welcome to Your Vue.js App', }; }, // add this filters: { reverseString(val) { let value = val; if (!value) return ''; value = value.split('').reverse().join(''); return value; }, }, }; </script>
代码增多了,可是总体的语义化却更好。从 filters
的用法咱们能够看出:web
因此,filters
的缺点就很明显了:若是要计算结合多个数据不一样变化的状况,过滤器就没法适用了。这就要用到咱们下面提到的计算属性了。ajax
在 vue
中,也为咱们提供了computed
这个选项来处理数据,咱们称它为计算属性。当逻辑复杂的时候,咱们就应当使用 computed
计算属性了。计算属性使用起来很是简单,咱们仍是用上面的例子,使用计算属性来修改模板中的逻辑:数组
<template> <div class='hello'> <h1>{{ message.split('').reverse().join('') }}</h1> <h1>{{ message | reverseString }}</h1> <h1>{{ this.reversedMessageMethod() }}</h1> <!-- add this --> <h1>{{ reversedMessage }}</h1> </div> </template> <script> export default { name: 'HelloWorld', data() { return { message: 'Welcome to Your Vue.js App', }; }, filters: { reverseString(val) { let value = val; if (!value) return ''; value = value.split('').reverse().join(''); return value; }, }, // add this computed: { reversedMessage() { return this.message.split('').reverse().join(''); }, }, methods: { reversedMessageMethod() { return this.message.split('').reverse().join(''); }, }, }; </script>
和 method
选项的使用很是类似。咱们能够像绑定普通属性同样在模板中绑定计算属性。缓存
这两种方式的最终结果确实是彻底相同的。然而,不一样的是:计算属性是基于它们的依赖进行缓存的。什么意思呢?
只在相关依赖发生改变时它们才会从新求值。这就意味着只要 message
尚未发生改变,屡次访问 reversedMessage
计算属性会当即返回以前的计算结果,而没必要再次执行函数;而当数据有变化时,只要有一个数据发生变化,则会从新计算,来更新视图的改变。相比之下,每当触发从新渲染时,调用 methods
中的方法将总会再次执行函数。
咱们为何须要缓存?假设咱们有一个性能开销比较大的计算属性
A,它须要遍历一个巨大的数组并作大量的计算。而后咱们可能有其余的计算属性依赖于
A 。若是没有缓存,咱们将不可避免的屡次执行
A 的
getter
!
咱们来看看计算属性的具体应用场景:
一、微博发文
发微博的时候,有字数限制。在咱们输入文字的时候,输入框会计算咱们还能够输入多少字:
<template> <div> <textarea v-model='content' :maxlength='totalcount'></textarea> <p>你还能够输入{{reduceCount}}字</p> </div> </template> <script> export default { data() { return { totalcount: 200, // 总共只给输入200字 content: '', }; }, computed: { reduceCount() { return this.totalcount - this.content.length; }, }, }; </script>
经过一直监听输入的字符的长度来触发 computed
里的 reduceCount
方法,从新计算,而后返回给视图,让视图做出相应的变化。接下来咱们再看一个例子。
二、足球比赛
这个例子是一个足球比赛的结果播报板,咱们先看看最终的效果,再看代码:
效果 :
代码:
<template> <div> <h1>比赛时间:{{time}}s</h1> <h2>直播播报:{{result}}</h2> <div class='team'> <div> <p>中国队进球数:{{team.china}}</p> <button @click='team.china++'>点击中国队进一球</button> </div> <div> <p>韩国队进球数:{{team.korea}}</p> <button @click='team.korea++'>点击韩国队进一球</button> </div> </div> </div> </template> <script> export default { created() { const time = setInterval(() => { this.time = this.time + 1; if (this.time === 90) { clearInterval(time); } }, 1000); }, data() { return { time: 0, team: { china: 0, korea: 0, }, }; }, computed: { result() { if (this.time < 90) { if (this.team.china > this.team.korea) { return '中国队领先'; } else if (this.team.china < this.team.korea) { return '韩国队领先'; } return '双方僵持'; } if (this.team.china > this.team.korea) { return '中国队赢'; } else if (this.team.china < this.team.korea) { return '韩国队赢'; } return '平局'; }, }, }; </script> <style scoped> .team { display: flex; justify-content: center; } button { padding: 15px 60px; outline: none; background-color: #27ae60; display: block; font-size: 1rem; color: #fff; margin: 10px; } </style>
经过上面的例子,咱们就能够很清楚 computed
的做用了:观察一个或者多个数据,只要依赖的数据发生变化的时,这个函数就会从新计算。这样咱们就能够经过观察全部数据来维护一个状态,也就是所谓的返回一个状态值。
虽然计算属性在大多数状况下更合适,但有时也须要一个自定义的侦听器。vue
经过 watch
选项提供了一个更通用的方法,来响应数据的变化。
computed
和 watch
均可以作同一件事,两个选项都是对数据进行时时监听。可是它们也有不一样:
computed
对多数据变更进行监听,返回一个状态,维护一个状态watch
是对一个数据监听,在数据变化时,会返回两个值,一个是 value
(当前值),二是 oldvalue
是变化前的值咱们也能够用 watch
选项来改造上面的足球比赛的例子,添加一个 watch
选项:
<script> export default { created() { const time = setInterval(() => { this.time = this.time + 1; if (this.time === 90) { clearInterval(time); } }, 1000); }, data() { return { time: 0, team: { china: 0, korea: 0, }, }; }, // add this watch: { time(value, oldval) { // eslint-disable-line if (value < 90) { if (this.team.china > this.team.korea) { this.result = '中国队领先'; } else if (this.team.china < this.team.korea) { this.result = '韩国队领先'; } else { this.result = '双方僵持'; } } else if (this.team.china > this.team.korea) { this.result = '中国队赢'; } else if (this.team.china < this.team.korea) { this.result = '韩国队赢'; } else { this.result = '平局'; } }, team(value, oldval) { // eslint-disable-line if (this.time < 90) { if (value.china > value.korea) { this.result = '中国队领先'; } else if (value.china < value.korea) { this.result = '韩国队领先'; } else { this.result = '双方僵持'; } } else if (value.china > value.korea) { this.result = '中国队赢'; } else if (value.china < value.korea) { this.result = '韩国队赢'; } else { this.result = '平局'; } }, }, }; </script>
能够看出跟使用 computed
选项是差很少一致的。那 watch
有什么应用场景呢?
有一个很常见的场景:图片的预加载。当图片数量比较大的时候,为了保证页面图片都加载出来的时候,才把主页面给显示出来,而后再进行一些 ajax
请求,或者逻辑操做,这个时候用 computed
就没法实现了,只能用 watch
,看看代码:
<template> <div v-show='show'> <img src='https://img.alicdn.com/simba/img/TB14sYVQXXXXXc1XXXXSutbFXXX.jpg' alt> <img src='//img.alicdn.com/tfs/TB1iZ6EQXXXXXcsXFXXXXXXXXXX-520-280.jpg_q90_.webp' alt> <img src='https://img.alicdn.com/simba/img/TB1C0dOPXXXXXarapXXSutbFXXX.jpg' alt> <img src='//img.alicdn.com/tfs/TB1iZ6EQXXXXXcsXFXXXXXXXXXX-520-280.jpg_q90_.webp' alt> </div> </template> <script> export default { data() { return { count: 0, show: false, }; }, mounted() { const imgs = document.querySelectorAll('img'); console.log(imgs); // eslint-disable-line Array.from(imgs).forEach((item) => { const img = new Image(); img.onload = () => { this.count = this.count + 1; }; img.src = item.getAttribute('src'); }); }, watch: { count(val, oldval) { // eslint-disable-line if (val === 4) { this.show = true; alert('加载完毕'); // eslint-disable-line // 而后能够对后台发送一些ajax操做 } }, }, }; </script>
咱们能够发现等四张图片都加载完毕的时候页面才显示出来。因此当咱们想要在数据变化响应时,执行异步操做或开销较大的操做,就须要使用 watch
了。
过滤器 filter
:
计算属性 computed
:
侦听器 watch
:
value
(当前值),二是 oldvalue
是变化前的值
注:本节内容的
demo
均来自
混元霹雳手,感谢做者!
欢迎关注个人博客: https://togoblog.cn/