2018年9月30日,尤雨溪在medium个人博客上发布了vue3.0的开发思路。3.0带了了很大的变化,他讲了一些改进的思路以及整个开发流程的规划。对2.0有了全面的提升,并且源码全部用typescript重写,所以typescript刻不容缓。本文章翻译自国外大牛的文章,文章。
以下为翻译
最近,Typescript在Javascript生态系统中变得越来越流行,通过这篇文章,我不想深入研究Typescript,但我想展示一个基本方法,整合Vuex在Vue应用程序中与Typescript代码库集成。 此时,我假设您熟悉基本的Typescript方法以及如何在Vue应用程序中使用该语言。 如果您想查看一个基本的TS示例,我建议您查看此repo:https:
根据官方文档,Vuex的定义方式如下: Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
由于我对Flux和Redux有丰富的经验,这个概念对我来说听起来并不新鲜,所以如果你熟悉这个模式,那么获取它并开始使用Vuex应该不是什么大问题。 在我看来,这种模式在处理需要扩展和提高整体生产力的应用程序时非常有用。 回到这一点,我们如何将Vuex与Typescript结合起来?
首先,让我们在index.ts中初始化并暴露store: index.ts文件
// index.tsimport Vue from 'vue';import Vuex, { StoreOptions } from 'vuex';import { RootState } from './types';import { profile } from './profile/index';Vue.use(Vuex);const store: StoreOptions= { state: { version: '1.0.0' // a simple property }, modules: { profile }};export default new Vuex.Store (store);复制代码
typescript特有的types.ts文件:
// types.tsexport interface RootState { version: string;}复制代码
这些代码与创建一个标准Vuex store非常相似,但你应该注意到稍显不同:
- 一个storeOpts变量应使用“StoreOptions”类型去创建,并将泛型类型定义为“RootState”(定义根状态类型)
- 同样new Vuex.Store需使用RootState类型。
由于存在这些差异,我们需要在根Vuex实例去明确定义这些types。 一般来说,我建议并推荐采用模块化方法,因为将Vuex连接到多个组件时有很多优点,所以我在store中放置了一个简单的基本模块:Profile。
// profile/index.tsimport { Module } from 'vuex';import { getters } from './getters';import { actions } from './actions';import { mutations } from './mutations';import { ProfileState } from './types';import { RootState } from '../types';export const state: ProfileState = { user: undefined, error: false};const namespaced: boolean = true;export const profile: Module= { namespaced, state, getters, actions, mutations};复制代码
types.ts:
// types.tsexport interface User { firstName: string; lastName: string; email: string; phone?: string;}export interface ProfileState { user?: User; error: boolean;}复制代码
看一下index.ts文件,您可能会注意到以下几点:
- State被profilestate type初始化了
- 在这个阶段,创建和导出的模块有点复杂:它是一个定义两种类型的模块:ProfileState(模块状态)和RootState(Vuex存储的根状态)
Module是Vuex声明的interface文件:
// vuex/types/index.d.tsexport interface Module{ namespaced?: boolean; state?: S | (() => S); getters?: GetterTree; actions?: ActionTree; mutations?: MutationTree; modules?: ModuleTree;}复制代码
看一下暴露类型,Module是一个简单的对象,将actions / mutation / getters / state聚合(可选)起来的和内部模块化策略。 我们来看看示例中的Actions。
Actions.ts:
// profile/actions.tsimport { ActionTree } from 'vuex';import axios from 'axios';import { ProfileState, User } from './types';import { RootState } from '../types';export const actions: ActionTree= { fetchData({ commit }): any { axios({ url: 'https://....' }).then((response) => { const payload: User = response && response.data; commit('profileLoaded', payload); }, (error) => { console.log(error); commit('profileError'); }); }};复制代码
为了导出正确的Module类型,我们需要将我们actions设置为ActionTree类型,这是Vuex中定义的类型,如:
// vuex/types/index.d.tsexport interface ActionTree{ [key: string]: Action;}复制代码
这并不难以理解,它代表ActionTree的键对象,定义了Action的名称,以及与之相关的Action(仍然期望Module State和根State类型)。
本例中,我们只有一个ActionTree,它只有一个fetchData的action,它执行异步任务(从服务中检索一些数据)并根据网络响应提交成功或错误。 如果成功,将向用户输入有效负载。复制代码
接下来mutations:
// profile/mutations.tsimport { MutationTree } from 'vuex';import { ProfileState, User } from './types';export const mutations: MutationTree= { profileLoaded(state, payload: User) { state.error = false; state.user = payload; }, profileError(state) { state.error = true; state.user = undefined; }};复制代码
Mutations与我们为Actions讨论的相同方法,并期望由Vuex定义的MutationTree类型的变量,如下所示:
// vuex/types/index.d.tsexport interface MutationTree{ [key: string]: Mutation;}复制代码
为了关闭模块的初始化,我们也暴露了所需的getter。 在我们的例子中,一个简单的getter返回所选用户的全名可能就足够了,它结合了存储的firstName和lastName属性。 是的,您甚至可以在User中使用class,但这里只是一个基本的getter示例。
Getters.ts
// profile/getters.tsimport { GetterTree } from 'vuex';import { ProfileState } from './types';import { RootState } from '../types';export const getters: GetterTree= { fullName(state): string { const { user } = state; const firstName = (user && user.firstName) || ''; const lastName = (user && user.lastName) || ''; return `${firstName} ${lastName}`; }};复制代码
在Vuex中定义如下
// vuex/types/index.d.tsexport interface GetterTree{ [key: string]: Getter;}复制代码
现在,最重要的部分:我们如何将所有内容连接到Vue组件? 如下,我使用将简单组件连接到Vuex。
复制代码Full name: {
{ fullName }}Email: {
{ email }}Oops an error occured
上面的例子是一个非常基本的例子。 包含template的单文件组件和暴露组件的typescript。
在该示例中,我还使用来使用基于类的Vue组件(也是vuex-class的依赖项)。 感谢,可以使用装饰器来获得我们需要的东西:State,Actions,Mutations,Getters和namespaced decorators。
我们的组件有一些计算变量即computed,一个是由@State引入的profile,指的是Profile的状态,另一个是我们在模块中定义的getter:get email()。
此示例使用由vuex-class公开的两个显式装饰器:State和Getter。
为了访问正确的模块,将具有namespace作为属性的对象(或BindingOptions)作为第二个参数传递。
@State('profile') profile: ProfileState;@Getter('fullName', { namespace }) fullName: string;复制代码
当然,在profile的vuex中需要定义fetchData的Action,组件中才能使用
@Action('fetchData', { namespace }) fetchData: any;复制代码
并且在mounted中使用fetchData
mounted() { // fetching data as soon as the component's been mounted this.fetchData();}复制代码
为了渲染正确,模板的一部分是使用先前定义的getter来显示fullName和get email() 来获取User的email。
Full name: {
{ fullName }}Email: {
{ email }}复制代码
基本上就是这样。还有其他方法可以将Vue组件与Vuex连接,但我相信这是一种有效的入门方式。当然,在给定的示例中存在很大的改进空间,如增强代码的类型检查使逻辑更加清晰,或通过更好的方式来呈现模块的渲染。我希望你喜欢这篇文章!
以上为翻译内容,若有不正确之处,请不吝指出。
github上用Vue-CLI3搭了个ts+vuex小例子