工作記錄:TypeScript從入門到項目實戰(項目篇)


Vue項目中使用

前面兩篇介紹過TypeScript基礎和較深入的東西,本章介紹如何在Vue項目中使用。

項目創建

創建項目直接使用Vue-cli創建

下面是步驟:

1.運行vuecli,

2.選擇合適的目錄創建項目

3.輸入項目名並,選擇包管理器,輸入git倉庫初始化內容

4.設置預設,如果你之前有合適的預設,可以設置該預設,這里選擇手動

5.選擇功能,其中TypeScript和babel必選,其他功能視項目而定:

6.設置配置,開啟類樣式組件語法(第一項),選擇eslint配置為ESLint+Standard(第五項),開啟保存時檢查和修復代碼

7.創建項目

8.安裝一些插件

編輯器文件支持設置

這里以我們以后統一使用的Webstrom為例:

找到Editor>File and COde Templates

 

新建一個代碼模板,輸入名稱,擴展名為vue,選擇根據樣式重新設置格式、選擇啟用該模板

 

內容區域輸入:

<template lang="pug">
#[[$END$]]#
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component
export default class ${COMPONENT_NAME} extends Vue {
  
}
</script>

<style  lang="stylus" rel="stylesheet/stylus" module>

</style>

點擊應用之后,新建文件時選擇剛建立的模板:

因為選擇的是類樣式語法,所以需要填入類名:

 

修改eslint、編輯器配置

修改eslint配置文件以支持檢查TypeScript文件 

.eslintrc.js文件的parserOptions選項中新增如下代碼:

parser: '@typescript-eslint/parser'

修改編輯器配置以支持保存時自動修復代碼

webstrom強大之處是對各種技術的支持,比如eslint檢查代碼。正常情況下,我們需要通過命令行檢查代碼,這非常麻煩,不過webstrom能夠配置eslint,編輯器內檢查不合eslint配置的代碼,並且支持保存時修復。配置如下:

 

修改聲明文件

對於我們自定義的插件、全局方法、全局變量等,TypeScript並不知道他們,為了讓TypeScript認識他們,我們可以通過聲明文件告訴TypeScript,如果使用model樣式時的$style,我們修改shims-tsx.d.ts文件,在行末添加下面代碼:

declare module 'vue/types/vue' {
  interface Vue {
    $style: {
      [key: string]: string;
    };
  }

  interface VueConstructor {
    $style: {
      [key: string]: string;
    };
  }
}

對於其他內容和上面方法類似

組件中使用

基本用法

因為使用類樣式寫組件中的js,所以寫法上會略有不同,但是本質上還是不變的。

組件引用

組件引用通過傳遞參數components給裝飾符@Component

@Component({
  components: {
    MapLegend: () => import('@/components/legend/index.vue')
  }
})

過濾器

過濾器和組件類似,通過傳遞filters參數,filters對象內定義局部過濾器:

@Component({
  filters: {
    dateFormat (date:Date) {
      return dateFormat(date)
    }
  }
})

指令

局部指令和過濾器類似,通過@Component裝飾器傳遞參數directives

@Component({
  directives:{
    focus: {
      inserted: function (el) {
        el.focus()
      }
    }
  }
})

props

props不再通過對象屬性形式定義,而是通過@Prop裝飾器定義,其配置內容通過參數形式傳入裝飾器:

@Component
export default class Test extends Vue {
  @Prop({
    type:String,
    default:'no name',
    required:false
  }) name!:string

  mounted(){
    console.log(name)
  }
}

props同步版

通過@PropSync可以創建一個props屬性的同步版本(即:變量改變,所對應的props屬性也會隨之改變):

@Component
export default class Test extends Vue {
  @PropSync('name',{
    type:String,
    default:'no name',
    required:false
  }) name!:string

  mounted(){
    this.name='nichols'
  }
}

偵聽器(watch)

類似的,偵聽器通過@Watch裝飾器定義,裝飾器接收兩個參數,第一個監視哪個變量,第二個其他配置:

@Component
export default class Test extends Vue {
  isShow=false
  @Watch('isShow',{
    deep:true,
    immediate:true
  })
  onIsShowChange(val:boolean,newVal:boolean){

  }
}

偵聽器同樣可以被當做方法調用,只是執行其內部邏輯:

  mounted(){
    this.onIsShowChange(true,false)
  }

emit

在組件中觸發事件讓父組件偵聽到是一個非常常用的操作,通過@Emit裝飾符定義,所定義的函數可以被當做普通函數調用:

@Component
export default class Test extends Vue {
  name = ''

  @Emit('change')
  onChange (name: string) {
    this.name = name
  }

  mounted () {
    this.onChange('nichols')
  }
}

其中如果有返回值,則返回值會作為觸發的參數放在前面,而傳入參數會放到返回值后面

ref

定義ref使用@Ref裝飾器定義:

@Component
export default class Test extends Vue {
  name = ''

  @Ref('form') form!:HTMLElement

  mounted(){
    console.log(this.form.offsetHeight)
  }
}

data

對於組件內的數據,我們可以直接使用類屬性定義組件的數據:

@Component
export default class Test extends Vue {
  isShow = false
  form: {
    username: string;
    password: string;
  } = {
    username: '',
    password: ''
  }

  mounted () {
    this.isShow = true
  }
}

函數(methods)

函數與data定義類似,為類添加一個方法即可:

@Component
export default class Test extends Vue {
  log(){
    // ....
  }
}

計算屬性

而計算屬性,則是類的存取器的寫法(gettersetter,對應Vue的gettersetter):

@Component
export default class Test extends Vue {
  lastName = '尼古拉斯'
  firstName = '趙四'

  get name (): string {
    return `${this.firstName}·${this.lastName}`
  }

  set name (name: string) {
    const names = name.split('·')
    this.firstName = names[0]
    this.lastName = names[0]
  }
}

生命周期

可以直接定義所對應的鈎子名稱,或者借助vue-class-component/hooks.d.ts完成:

@Component
export default class Test extends Vue {
  mounted () {
  }

  created () {
  }

  updated () {
  }

  beforeDestroy () {
  }

  destroyed () {
  }
}

更加詳細的內容

更詳細參考vue-property-decorator文檔

類型聲明

src目錄下types目錄下,創建index.d.ts(或者更詳細的文件名),然后定義類型,這里以擴展Event為例

interface Event{
  DataTransfer:{
    setData():void
  }
}

為了避免全局變量混亂,可以使用export導出我們想要被外部訪問的聲明:

export interface User{
  id:string;
  name:string;
  realName:string;
}

需要使用時,再在需要使用的地方導入即可:

import { User } from '@/types/user'

@Component
export default class Test extends Vue {
  user:User={
    id: '',
    name: '',
    realName: ''
  }
}

舊項目的遷移

安裝插件

1.啟動vue ui(一把梭,就是干!),在插件項中點擊添加插件,

2.搜索TypeScript,選擇@vue/cli-pluging-typescript,點擊安裝即可

修改組件

1.script標簽添加屬性lang="ts"

2.組件引入添加.vue后綴名

3.修改默認導出為類樣式:

export default {
  name:'Component1'
}

修改為:

@Component
export default class Component1 extends Vue{
}

4.按照基本用法,將對應的數據更改為類樣式

5.按照編輯器報錯提示添加或者修改類型注釋

修改js文件

1.js文件后綴改為.ts

2.添加類型約束

vuex的使用

vuex和vue組件使用方式類似,使用類樣式+裝飾器的形式定義,使用的依賴是vuex-module-decoratorsvuex-class

安裝

yarn add vuex-module-decorators vuex-class
npm i vuex-module-decorators vuex-class

創建Store

Store的創建和常規創建方式一致,只是Vuex.Store參數中無需傳入任何參數:

import Vue from 'vue'
import Vuex from 'vuex'
import User from '@/store/modules/user'
import getters from '@/store/getters'

Vue.use(Vuex)

export default new Vuex.Store({
})

定義模塊

@Module

使用@Module定義一個vuex模塊,接收如下參數:

 

屬性

數據類型

描述

name

string

模塊的名稱(如果有名稱空間)

namespaced

boolean

模塊是否具有名稱空間

stateFactory

boolean

是否開啟狀態工廠(方便模塊復用)

dynamic

true

如果這是一個動態模塊(在創建存儲后添加到存儲)

 

store

Store<any>

將注入此模塊的存儲區(用於動態模塊)

preserveState

boolean

如果啟用此選項,則加載模塊時將保留狀態

創建模塊語法如下:

import { VuexModule } from 'vuex-module-decorators'
@Module({
  dynamic: true,//啟用動態模塊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
}

state

state的定義和組件中的data定義類似:

@Module({
  dynamic: true,//啟用動態模塊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
  token = getToken()
}

上面代碼和下面代碼效果一樣:

export default {
	state:{
  	token: getToken()
  },
  namespaced:true
}

@Mutation

mutation的定義使用@Mutation裝飾器定義:

@Module({
  dynamic: true,//啟用動態模塊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
  token = getToken()

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }
}

@Action

使用@Action裝飾器定義action,該裝飾器接收三個參數:

 

參數名

類型

描述

commit

string

所提交的荷載

rawError

boolean

是否打印原始錯誤類型(默認會對報錯信息進行包裝)

root

boolean

是否允許提交根荷載

如果不傳入參數,需要手動提交荷載:

@Module({
  dynamic: true,//啟用動態模塊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
  token = getToken()

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }

  @Action
  async login () {
    this.context.commit('setToken', 'token')
    router.replace('/')
  }
}

如果指定提交的荷載名,可通過函數的返回值設定荷載值:

@Module({
  dynamic: true,//啟用動態模塊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
  token = getToken()

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }

  @Action({commit:'setToken'})
  async login ():string {
    router.replace('/')
    return 'token'
  }
}

@MutationAction  

有時候簡單地數據操作,mutation會顯得有點多余,這時候,我們可以使用@MutationAction裝飾器將mutatioin和action合二為一,用此裝飾器定義的action會同時定義並提交荷載:

@Module({
  dynamic: true,//啟用動態模塊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
  testStr = ''

  @MutationAction({ mutate: ['testStr'] })
  async setStr () {
    return new Promise<{ testStr: string }>(resolve => {
      resolve({
        testStr: 'test'
      })
    })
  }
}

需要注意的是:返回對象的數據結構必須和指定的參數名一致

getter

getter的定義和Vue組件中的計算屬性定義類似,使用get前置於方法名:

@Module
class MyModule extends VuexModule {
  wheels = 2

  get axles() {
    return this.wheels / 2
  }
}

完整示例

import {
  deleteRefreshToken,
  deleteToken,
  deleteUserInfo,
  getRefreshToken,
  getToken,
  getUserInfo,
  setRefreshToken,
  setToken,
  setUserInfo
} from '@/utils/auth'
import { UserInfo } from '@/types/user'
import router from '@/router'
import { Action, Module, Mutation, MutationAction, VuexModule } from 'vuex-module-decorators'

@Module({
  dynamic: true,//啟用動態模塊,模塊將在調用getModule時注冊
  name: 'User',
  store,//注入store
  namespaced: true,
  stateFactory: true//開啟工廠模式
})
export default class User extends VuexModule {
  token = getToken()
  refreshToken = getRefreshToken()
  userInfo: UserInfo | null = getUserInfo()
  testStr = ''

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }

  @Mutation
  setRefreshToken (token: string) {
    this.refreshToken = token
    token ? setRefreshToken(token) : deleteRefreshToken()
  }

  @Mutation
  setUserInfo (user: UserInfo | null) {
    this.userInfo = user
    user ? setUserInfo(user) : deleteUserInfo()
  }

  @MutationAction({ mutate: ['testStr'] })
  async setStr () {
    return new Promise<{ testStr: string }>(resolve => {
      resolve({
        testStr: 'test'
      })
    })
  }

  @Action
  async login () {
    this.context.commit('setToken', 'token')
    this.context.commit('setRefreshToken', 'refreshToken')
    this.context.commit('setUserInfo', {})
    router.replace('/')
  }

  @Action
  async loginOut () {
    this.context.commit('setToken', '')
    this.context.commit('setRefreshToken', '')
    this.context.commit('setUserInfo', null)
    router.replace('/login')
  }
}

組件中使用

組件中通過getModule()方法進行獲取到模塊,可以通過定義計算屬性以使用state

import { Component, Vue } from 'vue-property-decorator'
import User from '@/store/modules/user'
import { getModule } from 'vuex-module-decorators'
import { namespace } from 'vuex-class'

let user:User = getModule(User)

@Component
export default class test extends Vue {
  //動態數據,使用user.userInfo獲取的並不是響應式數據
  @namespace('User').State('userInfo') userInfo: UserInfo
  
  login ():void {
    console.log(user.testStr)
    user.login()
  }
  
  get token ():string {
    return user.token
  }

  mounted ():void {
    
  }
}

小程序中使用

小程序中使用TypeScript比較簡單,在創建項目時選擇語言為TypeScript,其他的和Vue類似項目類似

不同的是,Vue項目會自動編譯TypeScript,而小程序需要手動編譯ts文件,這顯得有點麻煩,所以我們可以使用webstrom開發小程序:

安裝小程序插件,讓webstrom支持小程序語法:File>Setting>Plugins,搜索Wechat mini programs upport,完成之后重啟webstrom,這時候我們可以看到在右鍵菜單New那一項里面多了兩個小程序選項:

配置ts文件自動編譯:File>Setting>Languages & Frameworks>TypeScript,選中改變時重新編譯:

 

擴展

本系列文章全面結合項目編寫,如果你還想深入學習TypeScript的話可以看下面的網站:

TypeScript中文網

TypeScript 入門教程 

TypeScript 學習資源合集

 

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM