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