uni-app中wach和computed的使用总结

最近做uni-app的项目,适配微信小程序.由于现在微信小程序出台了新的登录授权规范,根据规范和业务需求,首页共有3种展示状态:①未登录,②登录并且有全部权限,③登录有部分权限.该小程序的首页为购物车页面,业务相对复杂,考虑到状态的管理,使用了Vuex插件和watch的相关配合,现在将采坑记录下来.

计算属性 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>

   转载规则


《uni-app中wach和computed的使用总结》 刘星星 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
优化uni-app更新策略思路 优化uni-app更新策略思路
口语描述 全量更新: 全量更新是指发APP包更新,对应的iOS是指发IPA包到appstore,Android发apk包到商城。 增量更新: 指uni-app提供的热更新生成的wgt文件,可以下载完自动安装,然后重启APP即可完成更
2019-12-18
下一篇 
swift中Realm和objectbox的使用总结 swift中Realm和objectbox的使用总结
objectBoxobjectbox的优点请看官方的介绍。objectBox有各个语言版本。之前做Android项目的时候接触过objectBox的Java版本和Kotlin版本,处于“一招鲜吃遍天”的无耻想法,就一直关注着swift版
2019-11-23
  目录