搭建基于vue-cli3+typescript的tsx開發(fā)模板

搭建vue-tsx風(fēng)格的開發(fā)模板

項(xiàng)目創(chuàng)建

使用vue-cli3+創(chuàng)建一個(gè)基于ts的模板:

vue create vue-tsx-template

# 或者使用vue ui進(jìn)入GUI模式創(chuàng)建
vue ui

創(chuàng)建的時(shí)候記得勾選typescript,css預(yù)處理器看各自喜好選擇,選擇內(nèi)容如下:

初始化選項(xiàng)

等待npm/yarn安裝結(jié)束后就是一個(gè)基于tsvue模板了。

vue-tsx-support

上一步中已經(jīng)創(chuàng)建完了基于tsvue模板,但是開發(fā)方式還是如同之前的template一樣,只是將script中的js部分改成了ts來書寫。接下來就將模板(template)方式改成tsx的方式,這里需要借助一個(gè)庫 -- vue-tsx-support

首先安裝vue-tsx-support

npm install vue-tsx-support --save
# or
yarn add vue-tsx-support

安裝結(jié)束后,我們需要對我們的文件做點(diǎn)小改動,首先我們在主入口文件main.ts中引入:

// main.ts
import "vue-tsx-support/enable-check";

// 省略。。

然后刪掉src/shims-tsx.d.ts文件,避免和vue-tsx-support/enable-check聲明重復(fù)沖突。

最后在我們的vue.config.js文件里的configureWebpack屬性下增加一項(xiàng)resolve

// vue.config.js

module.exports = {
  // ...
  configureWebpack: {
    resolve: {
      extensions: [".js", ".vue", ".json", ".ts", ".tsx"] // 加入ts 和 tsx
    }
  }
}

這樣就可以了,接下來就可以開始開發(fā)了。

我們在/components下新建一個(gè)button文件夾,并創(chuàng)建一個(gè)文件button.tsx。然后開始書寫我們tsx風(fēng)格的vue代碼:

// components/button/button.tsx
import { Component, Prop } from "vue-property-decorator";
import * as tsc from "vue-tsx-support";

interface ButtonClick {
  (value: string): void
}

interface ButtonProps {
  text: string;
  btnClick?: ButtonClick
}

@Component
export default class ZButton extends tsc.Component<ButtonProps> {
  @Prop() text!: string;

  public btnClick(value: string): void {
    console.log("value is: ", value);
  }

  protected render() {
    return (
      <div>
        <button onClick={() =>  this.btnClick("click")}>{this.text}</button>
      </div>
    )
  }
}

這樣我們就完成了一個(gè)簡單的tsx組件了。

接下來我們需要去views/Home.tsx中使用這個(gè)組件,刪掉原來的Home.vue,并創(chuàng)建一個(gè)Home.tsx

// views/Home.tsx
import { Component, Vue } from "vue-property-decorator";
import { Component as tsc } from "vue-tsx-support";
import ZButton from "@/components/button/button.tsx";

@Component
export default class HomeContainer extends tsc<Vue> {
  protected render() {
    return <Zbutton text="點(diǎn)我!"></Zbutton>;
  }
}

最后將App.vue改成App.tsx

// App.tsx
import { Component, Vue } from "vue-property-decorator";

@Component
export default class App extends Vue {
  protected render() {
    return (
      <div id="app">
        <router-view></router-view>
      </div>
    );
  }
}

然后運(yùn)行,能看到以下效果:


運(yùn)行結(jié)果

就這樣完成了一個(gè)簡單的tsx風(fēng)格的vue項(xiàng)目了。

mixins

新建mixins/index.ts,在index.ts中寫一個(gè)vue mixin

// mixins/index.ts
import { Vue, Component } from "vue-property-decorator";

// 這里一定要做個(gè)聲明 不然在組件里使用的時(shí)候會報(bào)不存在的錯(cuò)誤
// 要對應(yīng)mixin中的屬性和方法
declare module "vue/types/vue" {
  interface Vue {
    mixinText: string;
    showMixinText(): void;
  }
}

@Component
export default class MixinTest extends Vue {
  public mixinText: string = "我是一個(gè)mixin";

  public showMixinText() {
    console.log(this.mixinText);
  }
}

然后在component/button/button.tsx中使用:

// component/button/button.tsx
import { Component, Prop } from "vue-property-decorator";
import * as tsc from "vue-tsx-support";

import MixinTest from "@/mixins";

interface ButtonClick {
  (value: string): void;
}

interface ButtonProps {
  text: string;
  btnClick?: ButtonClick;
}

// 在Component裝飾器上注入mixin
@Component({
  mixins: [MixinTest]
})
export default class ZButton extends tsc.Component<ButtonProps> {
  @Prop() text!: string;

  public btnClick(value: string): void {
    console.log("value is: ", value);
  }

  // 點(diǎn)擊事件中調(diào)用mixin的方法
  protected render() {
    return (
      <div>
        <button onClick={() => this.showMixinText()}>{this.text}</button>
      </div>
    );
  }
}

vuex

vuexts改造主要有兩種方案,一種是基于vuex-class的方式,一種是基于vue-module-decorators的方式。

因?yàn)榫幋a習(xí)慣的原因,喜歡在書寫vuex的時(shí)候,一個(gè)module store的各個(gè)小模塊都單獨(dú)寫成一個(gè)文件,而vue-module-decorators則是一個(gè)module store對應(yīng)一個(gè)文件。所以在選擇上,我選擇了vuex-class,有需要的朋友也可以了解下vuex-module-decorators。

安裝vuex-class

npm install vue-class --save
#or
yarn add vuex-class

新建一個(gè)systemmodule,針對systemstore建立各自文件

  • state.ts
  • getter.ts
  • mutation.ts
  • mutation-type.ts
  • actions.ts

編寫一個(gè)簡單的例子,在vuex中存儲user信息。

先來編寫state中的內(nèi)容:

// store/modules/system/state.ts

interface SystemState {
  user: Object
}

const state: SystemState = {
  user: {}
}

export default state;

mutation-type.ts

// store/modules/system/mutation-type.ts
interface SystemMutationType {
  SET_USER_INFO: String;
}

const Mutation_Type: SystemMutationType = {
  SET_USER_INFO: "SET_USER_INFO"
}

export default Mutation_Type;

mutation.ts

// store/modules/system/mutation.ts
import type from "./mutation-type";

const mutation: any = {
  [type.SET_USER_INFO as string](state: SystemState, user: Object) {
    state.user = user;
  }
}

export default mutation;

action.ts

import type from "./mutation-type";
import { Commit } from "vuex";

export const cacheUser = (context: { commit: Commit }, user: Object) => {
  context.commit(type.SET_USER_INFO as string, user);
}

然后建立一個(gè)index.ts將這些外拋出去:

// store/modules/system/index.ts
import state from "./state";
import mutations from "./mutation";
import * as actions from "./action";
import * as getters from "./getter";

export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
};

最后在store的入口文件處引用該module

// store/index.ts
import Vue from "vue";
import Vuex from "vuex";
import system from "./modules/system";

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    system
  }
});

接著我們?nèi)ソM件button.tsx中使用:

// components/button/button.tsx
import { Component, Prop } from "vue-property-decorator";
import * as tsc from "vue-tsx-support";
// 引入store命名空間 方便使用某個(gè)模塊
import { namespace } from "vuex-class";

// 通過namespace(module name)的方式使用某個(gè)模塊的store
const systemStore = namespace("system");

@Component
export default class ZButton extends tsc.Component<ButtonProps> {
  @Prop() text!: string;
  // store使用state和action 其他getter和mutation類型
  @systemStore.State("user") user!: Object;
  @systemStore.Action("cacheUser") cacheUser: any;

  public btnClick(value: string): void {
    console.log("value is: ", value);
    // 點(diǎn)擊調(diào)用store的action方式存儲user信息
    // 而state中的user信息會同步 可通過vue-tools查看
    this.cacheUser({ name: "張三", phone: "13333333333" });
  }

  // 點(diǎn)擊事件中調(diào)用mixin的方法
  protected render() {
    return (
      <div>
        <button onClick={() => this.btnClick()}>{this.text}</button>
      </div>
    );
  }
}

三方組件庫

目前主流的三方組件庫都是支持ts的,且官方文檔上都會提供ts下的demo以及配置。這里以有贊的vant作為例子。

安裝:

npm install vant --save
#or
yarn add vant

ts下如果想要按需加載vant的話,就不能使用babel-plugin-import了,而是要使用ts-import-plugin。

安裝ts-import-plugin

npm install ts-import-plugin --save-dev
#or
yarn add ts-import-plugin -D

安裝結(jié)束后,需要在vue.config.js中注入到webpack中使用:

// vue.config.js
const merge = require("webpack-merge");
const tsImportPluginFactory = require("ts-import-plugin");

// 將ts-import-plugin合并到webpack配置中
const webpackMergeConfig = config => {
  config.module
    .rule("ts")
    .use("ts-loader")
    .tap(options => {
      options = merge(options, {
        transpileOnly: true,
        getCustomTransformers: () => ({
          before: [
            tsImportPluginFactory({
              libraryName: "vant",
              libraryDirectory: "es",
              style: true
            })
          ]
        }),
        compilerOptions: {
          module: "es2015"
        }
      });
      return options;
    });
}

module.exports = {
  chainWebpack: config => {
    webpackMergeConfig(config);
    // ...省略
  }
}

然后就可以在組件文件中使用vant三方組件庫了:

// components/index.ts
import Vue from "vue";
import { Button } from "vant";

Vue.use(Button);

button.tsx

// components/button/button.tsx
import { Component, Prop } from "vue-property-decorator";
import * as tsc from "vue-tsx-support";

@Component
export default class ZButton extends tsc.Component<ButtonProps> {
  @Prop() text!: string;

  public btnClick(value: string): void {
    console.log("value is: ", value);
  }

  // 點(diǎn)擊事件中調(diào)用mixin的方法
  protected render() {
    return (
      <div>
        // 使用van-button
        <van-button type="primary">我是vant button</van-button>
      </div>
    );
  }
}

這里有個(gè)問題需要注意,在ts下打包的應(yīng)用會丟失三方組件庫的樣式,而在開發(fā)環(huán)境是沒有問題的。而導(dǎo)致該問題的發(fā)生是ts-loader不支持多線程打包
解決方式為在vue.config.js中配置parallel: false即可。

歡迎star vue-tsx-template

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容