# 在 NativeScript-Vue 应用程序中使用 Vuex-现在使用 Cats!
在上一篇文章中,我讨论了如何在 NativeScript 应用程序中使用 Vuex。Vuex 是一个非常复杂的主题,在上一个演示中我只涵盖了其中的一小部分,因此本文将添加更多细节,并纠正不包括任何猫的明显错误。对不起-老实说,我不知道自己在想什么。
# 应用程式
在进入代码之前,让我们快速看一下应用程序。这是一个相当简单的单页应用程序,它模拟照顾猫。对于那些年龄大到足以记住的人,可以将其视为手机的 Tamagotchi。打开应用程序后,您的猫咪会很高兴。
快乐的猫
当然,随着时间的流逝,您的猫通常对生活的满意度会降低。
中性猫
最终,当您-再次-失望时,它陷入了绝望的深渊。
疯狂的猫
如您所见,该应用程序分为三个部分。最上面是一张图片,代表猫的一般状态(以及我的艺术天赋的缩影),以及更直接的数字状态(主要用于测试,在此类“真实”游戏中将被删除),以及一个可以让您喂猫的按钮。
当您喂猫时,它会慢慢变得更快乐,但同时它也会变得更加饥饿,因此变得不那么快乐。拥有猫的任何人都会立即将这种矛盾理解为(猫)生活的简单事实。因此,让我们看一下它是如何构建的。
# 定义 Cat 商店
我的应用程序分为两部分-用于显示猫并与之交互的主要组件,以及表示虚拟猫数据并允许进行交互的 Vuex 存储。这个特定的 Vuex 演示将展示以前的 Getters 和 Actions 缺少的两个功能。
吸气剂的工作原理与计算后的 Vuex 属性类似。它们允许您定义需要封装某种逻辑的数据。让我们从查看猫的数据开始:
state: {
hungriness: 0
},
是的,就是这样。虚拟猫的整体由一个属性定义-它有多饿。但是,我们希望向应用程序展示猫的快乐程度,并且您可以想象,这是猫的饥饿程度的函数。吸气剂在一个getters
块中定义:
getters: {
happiness(state) {
// the more hungry, the less happy
return 100 - state.hungriness;
}
},
吸气剂传递到商店的状态,并且在状态更改时将自动更新。在应用程序方面,可通过来解决store.getters.happiness
。让我们看一个例子-图像和文本状态消息。
<Image :src="catImage" />
<Label textWrap="true" :text="status" />
这些都与计算属性有关:
computed: {
catImage() {
// get the status, which is a % from 0 to 100
let status = this.$store.getters.happiness;
if (status > 90) {
return "~/images/cat_happy.png";
} else if (status > 60) {
return "~/images/cat_medium.png";
} else return "~/images/cat_sad.png";
},
status() {
return "status is " + this.$store.getters.happiness;
}
}
尽管使用的吸气剂非常琐碎,但这里的好处是,随着 Cat 变得越来越复杂,它的幸福感背后的逻辑也可以更新。这是 Encapsulation 101,本身并不是什么新鲜的东西,但是再次可以看到 Vuex 如何真正使它易于使用。现在让我们看看 Vuex 的另一个功能-动作。
在上一篇文章中,我演示了 Mutations 是组件如何对商店进行更改的接口。突变必须是同步的,然后应该提出一个问题-如何进行异步更改。这是动作的发挥。
动作不会直接更改存储中的状态-而是也会使用突变。为了支持此操作,将一个context
对象传递给他们以支持进行更改。动作也可以采用任意参数。我们的猫有两个定义的动作。
第一个是“心跳”动作,它仅模拟时间的流逝。这就是让猫随着时间的推移变得饥饿(和不快乐)的原因。
actions: {
// more stuff here...
heartbeat(context) {
console.log('heartbeat started');
setInterval(() => {
console.log('heartbeat running');
context.commit('hunger');
}, HB_SPEED * 1000);
}
}
我setInterval
用来初始化定时重复的猫的生活。HB_SPEED 是一个常量变量,定义了它应该多久运行一次,我在测试时进行了调整,以寻找一种“好感觉”来使猫感到多么烦恼。注意这一行:
context.commit('hunger');
这就是操作通过突变请求更改的方式。在这种情况下,它只会使猫更加饥饿:
mutations: {
// more stuff here...
hunger(state) {
state.hungriness++;
if (state.hungriness > 100) state.hungriness = 100;
}
}
使用以下mounted
事件从主 Vue 组件触发心跳调用:
mounted() {
this.$store.dispatch("heartbeat");
},
动作的名称将作为第一个参数传递给商店,以后会随便添加任何其他参数。现在让我们看看另一个动作-喂猫。
feed(context) {
console.log('feed started');
setTimeout(() => {
context.commit('feed');
}, FEED_SPEED * 1000);
},
该feed
操作仅setTimeout
在对名为 feed 的变异进行提交调用之前包装了一个。为什么setTimeout
呢?只是为了模拟您喂猫时猫不会立即满足的情况。如果这看起来很武断和刻薄,那您可能是猫的新手。该feed
突变也有点乱:
feed(state) {
let satisfaction = getRandomInt(1, 10);
console.log('statisfaction was set to ' + satisfaction);
state.hungriness -= satisfaction;
if (state.hungriness < 0) state.hungriness = 0;
},
在这种情况下,我认为即使您每次给猫喂同样的东西,也不一定意味着猫每次都回应相同。还要注意一点逻辑,以确保饥饿感永远不会低于 0。
基本上就是这样,让我们 花点时间看一下整个商店:
import Vue from 'nativescript-vue';
import Vuex from '../vuex';
Vue.use(Vuex);
//number of seconds for updating
const HB_SPEED = 2;
// when you feed the cat, it takes a while for it to be satisfied from it. cuz cats
const FEED_SPEED = 8;
const catStore = new Vuex.Store({
state: {
hungriness: 0
},
getters: {
happiness(state) {
// the more hungry, the less happy
return 100 - state.hungriness;
}
},
mutations: {
feed(state) {
let satisfaction = getRandomInt(1, 10);
console.log('statisfaction was set to ' + satisfaction);
state.hungriness -= satisfaction;
if (state.hungriness < 0) state.hungriness = 0;
},
hunger(state) {
state.hungriness++;
if (state.hungriness > 100) state.hungriness = 100;
}
},
actions: {
feed(context) {
console.log('feed started');
setTimeout(() => {
context.commit('feed');
}, FEED_SPEED * 1000);
},
heartbeat(context) {
console.log('heartbeat started');
setInterval(() => {
console.log('heartbeat running');
context.commit('hunger');
}, HB_SPEED * 1000);
}
}
});
// Credit: https://stackoverflow.com/a/1527820/52160
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
module.exports = catStore;
从本质上讲,商店代表了猫的整体,并定义了集成,这两种事物都会改变状态,并会读取状态,以便任何组件都可以使用它。我们的应用程序只有一个主要组件,但可以轻松扩展到更多组件。这是主要组成部分:
<template>
<Page class="page">
<ActionBar title="Cat Simulator 95 XP Ultimate Edition" class="action-bar" />
<ScrollView>
<StackLayout class="home-panel">
<Image :src="catImage" />
<Label textWrap="true" :text="status" />
<Button text="Feed the Cat" @tap="feedCat" />
</StackLayout>
</ScrollView>
</Page>
</template>
<script>
export default {
data() {
return {};
},
mounted() {
this.$store.dispatch("heartbeat");
},
methods: {
feedCat() {
this.$store.dispatch("feed");
}
},
computed: {
catImage() {
// get the status, which is a % from 0 to 100
let status = this.$store.getters.happiness;
if (status > 90) {
return "~/images/cat_happy.png";
} else if (status > 60) {
return "~/images/cat_medium.png";
} else return "~/images/cat_sad.png";
},
status() {
return "status is " + this.$store.getters.happiness;
}
}
};
</script>
<style scoped>
.home-panel {
vertical-align: center;
font-size: 20;
margin: 15;
}
</style>
如果您想亲自尝试一下,则整个代码库都位于 NativeScript Playground 上。尽力使猫开心。您会失败,但还是要开心!