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小例子地址