教你搭建基於typescript的vue專案

小黎也發表於2018-09-23

自尤大去年9月推出vue對typescript的支援後,一直想開箱嘗試,對於前端sr來說,vue的順滑加上ts的物件導向,想著就非常美好~ 終於在兩個月前,找到了個機會嘗試了一把vue+ts的組合。 開文記錄下vue和ts整合之旅和遇到的一些坑。

vue

應該大部分人都知道vue,畢竟如今vue是與react肩並肩的存在,所以就不過多介紹啦。

vue中文官網 官網上的教程就是最好的入門教程

typescript

我在前幾篇文章就一直有在宣傳typescript,簡單列舉下ts的優點

  1. 始於JavaScript,歸於JavaScript,typescript是JavaScript的超集,所以它可以重用JavaScriptd程式碼,使用JavaScript的庫

  2. JavaScript用的優點它都有,跨瀏覽器、跨作業系統等

  3. 物件導向的程式設計思想,強大的型別檢查

  4. 開源大法好

要說缺點的話,那就是不太適合太小的專案。

就憑這些優點,足夠我們愉快的玩耍~

ts安裝

先將node安裝,然後在通過npm安裝ts的包

npm install -g typescript

tsc -v 檢視ts的版本號

建立專案

我們將通過官方提供的腳手架 vue-cli 來建立專案

安裝腳手架與建立專案

  1. 執行安裝命令

npm install -g @vue/cli

安裝完成後,可以通過 vue create 快速建立一個新專案的腳手架,或者直接通過 vue serve 構建新想法的原型。

  1. 建立專案 vue create vue-ts vue-ts是我們的專案名稱,執行後如下

vue-create

可看到有這麼幾個選項,xiaoli這個選項是我之前建立的,稍後會介紹;default這個後面寫著 babel eslint ,表示若選擇這個,那麼只會引入babel和 ealint;manually select features顧名思義,選擇我們想要的。那麼我們選擇第三個

教你搭建基於typescript的vue專案

可看到列表裡有很多選項,我們以vue+ts為主,所以我們選擇 babel typescript router vuex 這幾個,選擇完後,如下

教你搭建基於typescript的vue專案

接下來會有好幾個yes or no 的選項,大家根據自己專案的需要來選擇就可以,最後一步,Save this as a preset for future projects? 若選擇yes,就會將我們之前的選擇儲存起來,作為一個預設選項,方便後續一鍵建立新專案。所有步驟選完,回車,便開始建立專案檔案結構和拉取npm包

專案結構

專案結構如下

教你搭建基於typescript的vue專案
public: 用於存放靜態檔案,index.html入口檔案就放在裡面,這個資料夾下的檔案不會納入webpack的打包中;

src:存放vue專案工程檔案,其中已經幫我們關聯好router和vuex,檔案結構非常簡潔

其他:webpack、babel等配置檔案

與typescript服用

專案在構建中,已經引入 vue-class-component ,用於對ts的支援,或者使用 vue-property-decorator,這個庫是在之前那個的基礎上擴充套件。

以下列舉tsvue寫法的各種變化

元件宣告

建立元件的方式變成如下

import { Component, Prop, Vue, Watch } from 'vue-property-decorator';

@Component
export default class Test extends Vue {

}
複製程式碼

data物件

通過建構函式建立data裡的資料

import { Component, Prop, Vue, Watch } from 'vue-property-decorator';

@Component
export default class Test extends Vue {
    private name: string;
    constructor() {
        super();
        this.name = 'xiaoli';
    }
}
複製程式碼

data裡的資料使用方式如下

public getName(){
    return this.name
}
複製程式碼

Prop宣告

@Prop() public msg: string;
@Prop({ default: 'default value' }) propB: string
@Prop([String, Boolean]) propC: string | boolean
複製程式碼

生命週期函式使用

public created(): void {
    console.log('created');
}

public mounted():void{
    console.log('mounted')
}
複製程式碼

自定義方法

js下是需要在method物件中宣告方法,現變成如下

public clickFunc(): void {
    console.log(this.name)
    console.log(this.msg)
}
複製程式碼

Watch監聽屬性

@Watch('name',{ immediate: true, deep: true })
public onChildChanged(val: string, oldVal: string) {
    console.log('watch new name=' + val);
}
複製程式碼

computed計算屬性

public get allname() {
    return 'computed ' + this.name;
}
複製程式碼

allname是計算後的值,name是被監聽的值

emit事件

@Emit()
  addToCount(n: number) {
    this.count += n
  }

  @Emit('reset')
  resetCount() {
    this.count = 0
  }
複製程式碼

第一個的事件名稱為 add-to-count,n為傳過去的引數;第二個事件名為reset-count,引數為空

指令和過濾器

----------小小更新一下---------------

有小夥伴問指令和過濾器在ts下的寫法,之前給遺漏了,現在補充一下。

我嘗試了下,發現之前在入口檔案直接引入指令或者過濾器的方式不管用了,因為用了ts後,元件的作用域跟之前的不一樣了,然後我找了官方的issue,截圖如下

教你搭建基於typescript的vue專案

在作者在4月11號回覆裡,承認了這個問題,但具體什麼時候將指令和過濾器的宣告加上就未知了,不過作者在issue中給出瞭解決方案。我寫個簡單的小栗子

一個自定義指令

// ./directive/index.ts
export const focus = {
    // 當被繫結的元素插入到 DOM 中時……
    inserted: function (el:HTMLElement) {
        // 聚焦元素
        el.focus()
      }
}
複製程式碼

一個過濾器

// ./filter/index.ts
export const capitalize = function (value:string) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
}
複製程式碼

元件中使用

import { capitalize }from '@/filter/index'
import { focus } from '@/directive/index'
@Component({
    filters:{capitalize},
    directives:{focus}
})
export default class Test extends Vue {}
複製程式碼
<div>
    <input v-focus v-model="modelData">
    <div>{{modelData | capitalize}}</div>
</div>
複製程式碼

可看出這是區域性引用,全域性引用目前還沒找到辦法,歡迎有解決辦法的小夥伴指教~

vuex與ts的糅合

因為vuex是個可選的,所以單獨列出來。首先需要引用 vuex-class 庫,該庫有如下幾個模組

import {
    namespace,
    Action,
    Getter,
    Mutation,
    State
} from 'vuex-class';
複製程式碼

分別對應vuex中的 action、getter、mutation等,使用ts對vuex的影響主要在元件對vuex的呼叫上,vuex的定義還是按照之前的寫法即可

@State('foo') stateFoo
@State(state => state.bar) stateBar
@Getter('foo') getterFoo
@Action('foo') actionFoo
@Mutation('foo') mutationFoo
@someModule.Getter('foo') moduleGetterFoo

// If the argument is omitted, use the property name
// for each state/getter/action/mutation type
@State foo
@Getter bar
@Action baz
@Mutation qux
複製程式碼

若不想使用vuex定義的方法名,可以自定義屬性名,因為都是定義在當前this上,所以直接使用this呼叫即可

this.getterFoo // -> store.getters.foo
this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
複製程式碼

小結

搭建完成後,就可以像後端一樣擼前端啦~

相關文章