# 在 NativeScript-Vue 应用程序中使用 Vuex
恭喜-您已决定开始构建本机移动应用程序,并希望使用 Vue.js 作为框架。大!现在您可能想知道-“基于 Web 的原始” Vue 开发的哪些方面会延续到 NativeScript 流程中?尽管不一定是一对一的翻译,但绝对可以继承的方面之一是(通常)需要 Vuex 之类的工具。
在本文中,我将演示如何将 Vuex 添加到 NativeScript-Vue 应用程序中,但更好的是,我将对 Vuex 进行基本介绍并描述为什么可以使用它。当我刚开始学习 Vue 时,这个“我何时需要它”特别令人困惑,因此,当您要在应用程序中使用它时,我将尽我所能使其清楚(就像有些泥泞!)。准备?让我们开始吧!
# Vuex 到底是什么?
Vuex 这样定义自己:
TIP
“ Vuex 是 Vue.js 应用程序的状态管理模式+库。它用作应用程序中所有组件的集中存储,其规则确保状态只能以可预测的方式进行更改。”
起初这可能没有意义,尤其是如果您在 NativeScript-Vue 之前使用 Vue 是在较简单的应用程序中,其中 Vue 用于向简单网页添加简单的交互性和其他更新。(有时,我认为 Vue 是现代开发人员的超级 jQuery 构建。)
但是,一旦开始构建稍微复杂的应用程序或具有多个组件的应用程序(这肯定是您在 NativeScript-Vue 中会遇到的问题),您就会发现在多个组件之间保持数据同步的问题。用户记录可能是整个应用程序中使用的东西,并且通过 Vuex 可以使每个组件(也许每个页面)一致地反映有关该用户的正确信息。
是的,使用 Vuex 需要做更多的工作,但是您会发现它提供的功能在 NativeScript-Vue 中确实发光。让我们从构建一个简单的示例开始,并展示 Vuex 如何发挥作用。
在进行第一个演示之前,我想指出,我将跳过 NativeScript。每当我学到一些东西时,我都会尽量简化我的测试用例。因此,对于第一个示例,我将仅使用 CodePen。下一个示例将其正确集成到真实的 NativeScript 移动应用程序中。
# 在 Vue 建造宇宙飞船!
让我们在 Vue 中建造一艘太空船!好吧,我试图将其保持在 2000 字以下,所以代替一艘太空飞船,如何控制一个非常有限的,具有两个系统的引擎-武器和武器的太空船呢?整个船具有一定的能量。我将创建一个由各种组件组成的面板,使您可以一次增加或减少一个系统的能量。因此,例如增加一个引擎的能量必须减少武器的能量。这是操作面板的屏幕截图。
控制面板
在此屏幕快照中,有一个主要的 Vue 应用程序和两个子组件,每个控件一个。这是布局代码。
<div id="app" v-cloak>
<h2>Current Status</h2>
<p>
Engines are at {{engines}} and weapons are at {{weapons}}.
</p>
<engine-control></engine-control>
<weapon-control></weapon-control>
</div>
不是很复杂吧?因此,让我们创建一个商店。
const shipStore = new Vuex.Store({
state: {
engines: 50,
weapons: 50
},
mutations: {
increaseEngines(state) {
if (state.engines < 100) {
state.engines++;
state.weapons--;
}
},
decreaseEngines(state) {
if (state.engines > 0) {
state.engines--;
state.weapons++;
}
},
increaseWeapons(state) {
if (state.weapons < 100) {
state.weapons++;
state.engines--;
}
},
decreaseWeapons(state) {
if (state.weapons > 0) {
state.weapons--;
state.engines++;
}
}
}
});
Vuex 商店可以包含许多不同的内容,但我将从两个主要方面开始简单介绍。该state
值非常类似于data
Vue 应用程序的一部分。它代表您的商店跟踪的信息。就我而言,这只是引擎和武器的能量计数。我最初将这两个值都设置为 50,以表示该船总共 100 个“单位”(无关紧要)。一个更高级的示例可以存储总值,然后以编程方式确定两个系统。
Mutatations
改变商店价值的方式。您的 Vue 应用程序可以直接访问状态值,但是通常您希望避免这种情况。这是一个很好的理由。我们不希望系统的总能量低于 0 或高于 100。突变可以解决这一问题。默认情况下,突变会传递当前状态值,但也可以传递其他参数。变异必须是同步的,但存储也通过来支持异步操作actions
。再说一次-让我们保持简单。
回顾一下-我定义了商店的初始状态,以及外部应用程序处理该数据的方式。
const app = new Vue({
el: '#app',
store: shipStore,
computed: {
engines() {
return this.$store.state.engines;
},
weapons() {
return this.$store.state.weapons;
}
}
});
因此,这里有两件事要注意。商店将传递到 Vue 构造函数中。我不需要这样做,但是这样做可以通过来自动将其提供给子组件this.$store
。现在请注意中的两种方法computed
。两者都访问this.$store.state
以返回每个组件的值。如果您还记得布局,这部分是这样工作的:
<h2>Current Status</h2>
<p>
Engines are at {{engines}} and weapons are at {{weapons}}.
</p>
如果您不想直接访问状态,或者想要computed
在商店内部进行类似操作,那么您很幸运。Vuex 商店支持与getters
一样工作的属性computed
。现在让我们看一下其中的一个组件(只是一个组件,因为它们实际上是相同的)。这是引擎组件。
Vue.component('engine-control', {
template: `
<form>
<fieldset>
<legend>Engine Controls</legend>
<button @click.prevent="increaseEngine">Increase Engine</button>
<button @click.prevent="decreaseEngine">Decrease Engine</button>
</fieldset>
</form>
`,
methods: {
increaseEngine() {
this.$store.commit('increaseEngines');
},
decreaseEngine() {
this.$store.commit('decreaseEngines');
}
}
});
这里的布局不太重要,但请看一下两种方法。在这两种情况下,我们都使用来访问商店突变this.$store.commit
。请注意,我只是传递突变的名称。我也可以传递其他数据。例如,我可能要添加“全能量!” 将所有能量转移到系统的选项。
您可以在此 CodePen 上查看所有代码并运行完整的示例:
见笔 飞船商店由雷蒙德·卡姆登(@cfjedimaster)上 CodePen。
显然,这是一个琐碎的示例,并且存储可能会适得其反,但是随着应用程序变得越来越复杂(因为它很少会以其他方式出现),存储成为与船舶有关的数据“真相”的中心位置。我的 Vue 应用程序可以将更多的精力放在 UI 问题上(单击按钮可以这样做),而商店则集中在集中应用程序的“逻辑”上。
# NativeScript,Vue 和 Vuex
现在让我们看一下我们刚刚构建的应用程序的 NativeScript 版本。对于此演示,我将使用 NativeScript Playground,因此您可以使用 NativeScript Playground Preview 应用程序自己运行此示例。让我们看一下完成的结果,然后我们可以深入研究代码。这是初始页面。我正在使用TabView
创建三个视图。
nativescript vue 应用程序-TabView
初始视图具有两个系统的基本状态。单击单个选项卡仅提供该系统的报告,并控制修改电源。
nativescript vue 应用程序-修改电源
那么我是如何构建的呢?我首先使用 Vue 模板创建了一个新的 Playground 应用。为了增加对 Vuex 的支持,我在资源管理器中使用了+号,并选择了 NPM 选项。
本机游乐场 vuex
然后,我在搜索字段中输入“ vuex”并选择了最新版本。
nativescript 游乐场 vuex 包
如果使用 CLI,则要添加对 Vuex 的支持时,将在创建项目时提示您。如果您决定以后增加对 Vuex 的支持,则需要npm install vuex --save
在终端中使用。文档将对此进行更深入的讨论。如果您熟悉 Vue CLI,则知道它也支持添加插件,但是您不想在 NativeScript Vue 应用程序中使用该选项。现在让我们看一下代码。我做的第一件事是创建我的商店。与 CodePen 示例不同,该示例位于其自己的文件中。我创建了一个文件夹store
,然后单击shipStore.js
。这是内容。
import Vue from 'nativescript-vue';
import Vuex from '../vuex';
Vue.use(Vuex);
const shipStore = new Vuex.Store({
state: {
engines: 50,
weapons: 50
},
mutations: {
increaseEngines(state) {
if (state.engines < 100) {
state.engines++;
state.weapons--;
}
},
decreaseEngines(state) {
if (state.engines > 0) {
state.engines--;
state.weapons++;
}
},
increaseWeapons(state) {
if (state.weapons < 100) {
state.weapons++;
state.engines--;
}
},
decreaseWeapons(state) {
if (state.weapons > 0) {
state.weapons--;
state.engines++;
}
}
}
});
module.exports = shipStore;
在大多数情况下,这并没有太大区别,但是请注意,我已经导入了 Vuex 并指定 Vue 将使用它。坦白讲,在我找到这个很好的例子之前,我根本不愿这么做。
我的下一个修改是对我的核心app.js
文件进行包括和注册商店的操作:
import Vue from 'nativescript-vue';
import Vuex from './vuex';
Vue.use(Vuex);
import SpaceShip from './components/SpaceShip';
import shipStore from './store/shipstore';
// Uncommment the following to see NativeScript-Vue output logs
// Vue.config.silent = false;
new Vue({
render: h => h('frame', [h(SpaceShip)]),
store: shipStore
}).$start();
同样,这与先前的示例非常相似。通过将商店传递给我的 Vue 组件,我的根应用程序和所有子组件将拥有它。现在让我们看一下该根组件。
<template>
<Page class="page">
<ActionBar title="Spaceship Info" class="action-bar" />
<TabView>
<TabViewItem title="Main Report">
<Label :text="status" />
</TabViewItem>
<TabViewItem title="Engines">
<Engines />
</TabViewItem>
<TabViewItem title="Weapons">
<Weapons />
</TabViewItem>
</TabView>
</Page>
</template>
<script>
import Engines from "./Engines";
import Weapons from "./Weapons";
export default {
data() {
return {};
},
components: {
Engines, Weapons
},
computed: {
status() {
return `Engines are at ${this.engines} and weapons are at ${this.weapons}.`;
},
engines() {
return this.$store.state.engines;
},
weapons() {
return this.$store.state.weapons;
}
}
};
</script>
在此示例中,主要区别在于用于生成我的布局的标签。div
我使用的是 NativeScript 布局和 UI 组件,而不是其他 HTML 标签。但是存储值的使用是完全相同的。现在让我们来看一下 Engine 组件。
<template>
<StackLayout>
<Label :text="status" />
<Button text="Increase Engines" @tap="increaseEngine" />
<Button text="Decrease Engines" @tap="decreaseEngine" />
</StackLayout>
</template>
<script>
export default {
data() {
return {};
},
computed: {
status() {
return `Engines currently at ${this.$store.state.engines}.`;
}
},
methods: {
increaseEngine() {
this.$store.commit("increaseEngines");
},
decreaseEngine() {
this.$store.commit("decreaseEngines");
}
}
};
</script>
和以前一样,这里唯一真正的变化是布局。我对商店的使用完全相同,这太棒了。作为熟悉 Vue 并熟悉 NativeScript 的人,这应该会让您感到更加安全。我确实向该组件添加了一些文本,因为 NativeScript 版本使用选项卡来一次显示一个视图。
TIP
您可以在此处找到完整的源代码。
但是等等-还有更多(是的,很多…)
这仅仅是使用 Vuex 的开始,但希望您会开始发现采用这种方法所获得的一些优势。在下一篇文章中,我将演示 Vuex 的更多功能,并构建更接近于实际应用程序的东西。