计算属性
一个嵌套数组对象
Vue.createApp({
data(){
retrun {
author:{
name: 'John Doe',
books:[
'dddddd',
'ssssss',
'gggggg'
]
}
}
}
})
根据author
来显示不同的消息
<div id = 'computed-basics'>
<p>已出版的书籍</p>
<span>{{ author.books.length >0 ? 'Yes': 'No'}}</span>
</div>
此时执行的计算取决于author.books
但如果多次包含此计算,则问题会变得更糟
所以,对于复杂逻辑,你都应该使用计算属性
基本例子
<div id = "computed-basics">
<p>已出版的书籍</p>
<span>
{{publishedBooksMessage}}
</span>
</div>
Vue.createApp({
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// 计算属性的 getter
publishedBooksMessage() {
// `this` 指向 vm 实例
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
}).mount('#computed-basics')
这里声明了一个计算属性publishedBooksMessage
计算属性缓存vs方法
上例,通过在表达式中调用方法也可以达到同样的效果
<p> {{calculateBooksMessage}}</p>
//在组件中
methods:{
calculateBooksMessage(){
retrun this.author.books.length>0 ? 'Yes':'NO'
}
}
同样的函数定义为方法,而不是一个计算属性
从最终结果来看,实现方法是完全相同的
不同的是计算属性将基于它们的响应依赖关系缓存
计算属性只会在相关响应式依赖发生改变时,才会重新计算
意味着author。books
没有发生改变,多次访问publishedBooksMessage
时计算属性会立即返回之前的计算结果
不必再次执行函数
这也同样意味着下面的计算属性永远不会更新,因为Date.now()
不是响应式依赖
computed:{
now(){
return Date.now()
}
}
为什么需要缓存呢?
假设一个性能开销比较大的计算属性list
,遍历数组需要大量计算
其他的计算属性依赖于list
如果没有缓存的话,需要大量的开销
计算属性的Setter
计算属性默认只有一个getter
,不过在需要时也可以提供一个setter
<div id="computed-basics">
<!-- 直接写入计算属性中的对象,将会显示get()方法返回的值。-->
<h1>{{ fullName }}</h1>
</div>
<script>
Vue.createApp({
data() {
return {
firstName: "约翰",
lastName: "史密斯"
}
},
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]
}
}
}
}).mount('#computed-basics')
</script>
现在再运行 vm.fullName = 'John Doe'
时
setter 会被调用,vm.firstName
和 vm.lastName
也会相应地被更新。
侦听器
虽然计算属性在大多数情况下更合适
但有时也需要一个自定义的侦听器
Vue
通过watch
选项提供了一个更通用的方法,来响应数据的变化
当需要在数据变化时执行异步或开销较大的操作时,这个方法是最有用的
<div id ="wathc-example">
<p>
询问一个yes/no问题:
<input v-model="question"/>
</p>
<p>{{answer}}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script>
//创建Vue,返回应用实例
const watchExampleVm = Vue.createApp({
data(){
retrun {
question:'', //问题
answer:'问题通常包含一个问号' //问题
}
},
watch:{//侦听器
//只要问题发生变化,这个函数就会发生变化
question(newQuestion,oldQuestion){
//判断问题是否包含?,如果有则调用getAnswer()函数
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
})
}
}
})
</script>.mount('#watch-example')
使用watch
选项允许执行异步操作(访问一个API
)
并设置一个执行该操作的条件
还可以使用命令式vm.$watch API
计算属性vs侦听器
观察和响应当前活动的实例上的数据变动:侦听属性
当有一些数据需要随着其它数据变动而变动时
通常更好的做法是使用计算属性