计算属性 computed
我们使用计算属性computed的场景还是很常见的.计算属性在处理一些复杂逻辑时是很有用的.相对于methods,效果上两个都是一样的,两者可以相互替换使用.但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。所以我们为了性能,可以优先考虑使用computed.现在假设我们有个”很复杂”的逻辑,现在将js代码展示出来:
<script>
export default {
computed: {
title() {
return this.$config.indexTitle
},
desc() {
return `我被调用了${this.invokeCount}次`
}
},
watch: {
title(newValue, oldValue) {
this.setTitle()
},
},
data() {
return {
invokeCount: 0,
}
},
onLoad() {
},
methods: {
setTitle() {
this.invokeCount += 1
},
gotoChangeTitle() {
this.title = Date.now()
}
}
}
</script>
title值为一个计算属性的get,我们同时watch了这个title,每次title值发生了切换,那么desc字段就自动加1.点击事件为gotoChangeTitle.
但是,此时如果触发gotoChangeTitle事件,则会发生报错:
VM423:1 [Vue warn]: Computed property "title" was assigned to but it has no setter.
(found in pages/index/index)
原因是我们直接更改了title,但是title是计算属性字段,我此时只是实现了title的get方法,没有实现set方法,如果直接更改title则会报没有setter的错误.
解决点击事件报错:
gotoChangeTitle() {
//直接更改赋值,此处的值为我们声明的全局变量
this.$config.indexTitle = `啦啦啦${Date.now()}`
}
这样,虽然点击触发gotoChangeTitle没有报错,并且也确实更改了this.$config.indexTitle的值,但是却没有跟新页面,原因是我们并没有在data()中声明可以被”绑定”到view中的字段.
解决办法:我们需要在data中创建一个字段叫做indexTitle, indexTitle既是”绑定”给页面,也是相当于computed的”中间值”
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{ title }}</text>
</view>
<view class="text-area">
<text class="title">{{ desc }}</text>
</view>
<button type="primary" @click="gotoChangeTitle">本页面更新title</button>
</view>
</template>
<script>
export default {
computed: {
title:{
get() {
// 使用data中的indexTitle
return this.indexTitle
},
set (value) {
// 更改title后,也需要将indexTitle和全局值做更改
this.indexTitle = value
this.$config.indexTitle = value
}
},
desc() {
return `我被调用了${this.invokeCount}次`
}
},
watch: {
title(newValue, oldValue) {
this.setTitle()
},
},
data() {
return {
invokeCount: 0,
indexTitle: this.$config.indexTitle
}
},
onLoad() {
},
methods: {
setTitle() {
this.invokeCount += 1
},
gotoChangeTitle() {
//此时,我们不再操作data中的indexTitle,而是操作computed中的title属性
this.title = `啦啦啦${Date.now()}`
}
}
}
</script>
使用全局变量进行状态管理
如果业务简单,可以考虑不使用vuex.而只是使用全局变量.但是如果使用全局变量的话,为了及时更新状态,你在同一个页面时,如果一个值得状态发生了改变,你需要更新本页面的多处状态,可以考虑使用watch来监听数据的改变.关于watch的使用,我会在下面讲到.如果是多个页面,那么你的状态更新为了保证及时和正确性,需要放在onshow()方法里面,每次执行onshow方法时重新赋值,为了避免不必要的性能开销,可以配合computed来使用.
现在,我们有2个页面index和home,两者都需要使用一个全局变量indexTitle,两个测试页面的代码基本一致,为了读者的易读,就把两个页面的完整代码粘贴出来:
<template>
<view class="content">
<view class="text-area"><text class="title">我是index页面</text></view>
<view class="text-area">
<text class="title">{{ title }}</text>
</view>
<view class="text-area">
<text class="title">{{ desc }}</text>
</view>
<button type="primary" @click="gotoChangeTitle">index页面更新title</button>
</view>
</template>
<script>
export default {
computed: {
title:{
get() {
// 使用data中的indexTitle
return this.indexTitle
},
set (value) {
// 更改title后,也需要将indexTitle和全局值做更改
this.indexTitle = value
this.$config.indexTitle = value
}
},
desc() {
return `我被调用了${this.invokeCount}次`
}
},
watch: {
title(newValue, oldValue) {
console.log('index----watch---title被调用了')
this.setTitle()
},
},
data() {
return {
invokeCount: 0,
indexTitle: ''
}
},
onLoad() {
},
onShow() {
console.log('onShow被调用了')
this.title = this.$config.indexTitle
},
methods: {
setTitle() {
this.invokeCount += 1
},
gotoChangeTitle() {
//此时,我们不再操作data中的indexTitle,而是操作computed中的title属性
this.title = `啦啦啦${Date.now()}`
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
<template>
<view class="content">
<view class="text-area"><text class="title">我是home页面</text></view>
<view class="text-area">
<text class="title">{{ title }}</text>
</view>
<view class="text-area">
<text class="title">{{ desc }}</text>
</view>
<button type="primary" @click="gotoChangeTitle">home页面更新title</button>
</view>
</template>
<script>
export default {
computed: {
title: {
get() {
// 使用data中的indexTitle
return this.indexTitle
},
set(value) {
// 更改title后,也需要将indexTitle和全局值做更改
this.indexTitle = value
this.$config.indexTitle = value
}
},
desc() {
return `我被调用了${this.invokeCount}次`
}
},
watch: {
title(newValue, oldValue) {
this.setTitle()
}
},
data() {
return {
invokeCount: 0,
indexTitle: ''
}
},
onLoad() {
},
onShow() {
this.title = this.$config.indexTitle
},
methods: {
setTitle() {
this.invokeCount += 1
},
gotoChangeTitle() {
//此时,我们不再操作data中的indexTitle,而是操作computed中的title属性
this.title = `啦啦啦${Date.now()}`
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>