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(){
// ....
}
}
計算屬性
而計算屬性,則是類的存取器的寫法(getter、setter,對應Vue的getter和setter):
@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 () {
}
}
更加詳細的內容
類型聲明
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-decorators和vuex-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的話可以看下面的網站:
如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

