前言
近幾個月來,關於Typescript的討論越來越多,在閱覽相關資料後,筆者也開始了自己的學習之旅,嘗試在Vue專案中使用,雖然其他大大也分享了相關的教程,但在實際使用過程中難免有所紕漏,抑或隨著時間出現更好的方式,因為就有了這篇文章,分享我的構建過程和一些使用技巧。
下面分享的分享內容將不會涉及過多 Typescript 概念,對 Typescript 尚未入門的朋友可以先把文章點贊收藏一下?,回頭再來閱讀,有過後端開發經驗的朋友,上手時間會更快一點,比如我在大學時期就學習過 Java語言。
? 建立專案
首先讓我們建立一個Vue專案,熟練地開啟命令列,輸入建立命令:
vue create vue-ts-demo
因為是Demo專案,特性依賴配置我僅額外選擇Typescript一項配置,剩下的可以根據自己需要和習慣配置,等待片刻就能完成構建過程了。?
? 目錄分析
可以從package.json
檔案中看到,與普通專案相比,開發依賴多了typescript
一項,執行依賴則是多了vue-class-component
和vue-property-decorator
,讓我看下他們的作用是什麼:
Vue-class-component:一個允許您以類風格的語法建立Vue元件的庫。更多介紹可檢視vue-class-component 官方文件
Vue-property-decorator:依賴於
vue-class-component
,它提供@Component
@Prop
@Watch
@Emit
等特性的裝飾器,與我們在普通專案中使用的特性相同
此外,src目錄下還多了兩個檔案:shims-vue.d.ts
和shims-tsx.d.ts
shims-vue.d.ts:讓
.ts
檔案能夠識別.vue
檔案
shims-tsx.d.ts:允許我們在專案是編寫
.tsx
檔案
然而在實際在開發中,我們需要引入第三方依賴,因此我更傾向於對shims-vue.d.ts
檔案進行簡單的改造
// shims-vue.d.ts
// 主要引入vue官方依賴和一些自定義的全域性外掛
import Vue from 'vue';
import VueRouter, { Route } from 'vue-router';
import { Store } from 'vuex';
declare module 'vue/types/vue' {
interface Vue {
$router: VueRouter;
$route: Route;
$message: any; // 一個全域性的提示外掛
}
}
複製程式碼
// 新建 vue.d.ts 檔案,與shims-vue.d.ts同一層級
// 這裡主要是宣告一些第三方依賴,避免在使用中出現報錯
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
declare module 'qrcode'; // 一個第三方的二維碼庫
declare module '*.scss'; // scss檔案
declare module '*.tsx'; // tsx檔案
declare module '*.js'; // js檔案
複製程式碼
最後,專案中一共有shims-vue.d.ts
vue.d.ts
shims-tsx.d.ts
三個宣告配置檔案
?️ 正式體驗
專案配置好了,下面我們來做個Demo,這裡選用的是Demo屆的傳統題材:TodoList
首先我們定義元件TodoItem.vue
,用作顯示待辦項,下面是說明和程式碼:
- script 標籤中需要宣告lang為ts;
- 通過
vue-property-decorator
引入Compoent、Prop、Vue - Todo的型別定義為ITodo的介面,包含 string 型別的 content 和 Date 型別的 time 兩個屬性;
- @Prop中比較常用的屬性有
required
和default
,分別設定必須項和預設值;
<template>
<div
class="todo-item"
@click="complete">
{{todo.content}}
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import ITodo from '@/types/ITodo' // { content: string, time: Date }
@Component({
name: 'TodoItem'
})
export default class extends Vue {
@Prop({ required: true }) private todo!: ITodo;
public complete () {
this.$emit('click')
}
}
</script>
複製程式碼
然後則是TodoList.vue
頁面,它用作新增待辦項和待辦項列表的顯示,說明和程式碼如下:
- 同上,我們需要引入 Todo 型別介面及
vue-property-decorator
; - 引入
TodoItem.vue
元件,並在 @Component 中 components 屬性中宣告; - 定義 Data、Computed、methods 時,常用private/public/protected 宣告作用域;
- 定義屬性時,可以不宣告屬性的型別,ts將自動根據初始值判斷型別,但宣告陣列時,若不宣告型別將出現報錯資訊,可比較程式碼中的
content
和todos
; - 定義computed時,使用get xxx() { return ... } 來定義,如下
todoCount
; - 在儲存輸入框內容的save方法中,我們需要執行一個 blur() 的操作,我們通過 $ref 獲取到輸入框,但此時若不顯式宣告型別,編輯器將會報錯,原因是 ts 無法獲悉我們獲取的元件型別,自然無法判斷 blur() 方法是否存在於元件上;
<template>
<div class="todo-container">
<div class="todo-header">? Todo List ?</div>
<div class="todo-content">
<!-- input field -->
<div class="title">新增</div>
<input
v-model="content"
ref="input"
placeholder="✏️ 寫點什麼唄..."
class="todo-input-field"
@keydown.enter="save"
/>
<div class="title">待完成{{todoCount}}</div>
<!-- todos -->
<todo-item
v-for="(todo, i) in todos"
:key="todo.time.getTime()"
:todo="todo"
@click="complete(i)"/>
<!-- default -->
<div v-show="todos.length <= 0" class="default-todo-content">
暫無待完成事項
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import ITodo from '@/types/ITodo'
import TodoItem from '@/components/TodoItem.vue'
@Component({
name: 'TodoList',
components: {
TodoItem
}
})
export default class extends Vue {
// 輸入框內容
private content = '';
// 待完成
private todos: ITodo[] = [
{ content: 'Sleep', time: new Date() }
];
get todoCount () {
const { length } = this.todos
return length > 0 ? `(共${length}項)` : ''
}
// 將待辦項設為完成
public complete (index: number) {
this.todos.splice(index, 1)
}
// 儲存輸入框內容
public save () {
this.todos.push({
content: this.content,
time: new Date()
})
this.content = '';
// 取消聚焦
(this.$refs.input as HTMLInputElement).blur()
}
}
</script>
複製程式碼
頁面效果:
? ️擴充:如何在Typesctipt中使用Vuex
Vuex 在許多大中型專案中都有用到,下面就介紹一下它在Typescript中的一些使用技巧,我們繼續以上面的 TodoList 作為切入點,我使用的是vuex-module-decorators
,Github地址,它的使用方法與vue-property-decorator
相類似,讓我為大家娓娓道來。
首先通過npm install -D vuex-module-decorators
進行安裝;
然後改造store,在src/store
中新建modules
資料夾,新建檔案todo.ts
,相類似地,從vuex-module-decorators
引入相關模組,然後以@的形式宣告,程式碼內容如下:
// src/store/modules/todo.ts
import { VuexModule, Module, Mutation, Action, getModule } from 'vuex-module-decorators'
import store from '@/store'
import ITodo from '@/types/ITodo'
interface TodoStore {
trashes: ITodo[];
}
@Module({ dynamic: true, store, name: 'config' })
class TodoStore extends VuexModule implements TodoStore {
// 已完成列表
public trashes: ITodo[] = [];
// 加入已完成列表
@Mutation
private ADD_TRASH (todo: ITodo) {
this.trashes.push(todo)
}
// 加入已完成列表
@Action({ rawError: false })
public addTrash (todo: ITodo) {
this.ADD_TRASH(todo)
}
};
export const TodoStoreModule = getModule(TodoStore)
複製程式碼
然後改造src/store/index.ts
檔案,內容如下:
import Vue from 'vue'
import Vuex from 'vuex'
import { TodoState } from '@/store/modules/todo'
Vue.use(Vuex)
export interface RootState {
todoStore: TodoState;
}
export default new Vuex.Store<RootState>({})
複製程式碼
然後在TodoList.vue
頁面中引入,並對 TodoList 進行一定的升級,已完成的專案將被放入 store 中:
- 頁面新增顯示已完成列表
<template>
<div class="title">已完成{{trashCount}}</div>
<!-- todos -->
<todo-item
v-for="todo in trashes"
:key="todo.time.getTime()"
type="trash"
:todo="todo"/>
<!-- default -->
<div v-show="trashes.length <= 0" class="default-todo-content">
暫無已完成事項
</div>
</div>
</template>
<script lang="ts">
import { TodoStoreModule } from '@/store/modules/todo'
@Component({
name: 'TodoList',
components: {
TodoItem
}
})
export default class extends Vue {
// 已完成數量
get trashCount () {
return TodoStoreModule.trashCount > 0
? `(共${TodoStoreModule.trashCount}項)`
: ''
}
// 已完成數量
get trashes () {
return TodoStoreModule.trashes
}
// 將待辦項設為完成
public complete (index: number) {
const targetTodo = this.todos.splice(index, 1)
TodoStoreModule.addTrash(targetTodo[0])
}
}
</script>
複製程式碼
頁面效果:
⌚️ 最後
以上就是這篇文章的全部內容了,完整專案已上傳至我的Github倉庫。感謝各位老哥,各位老妹的閱讀,第一次分享文章,可能會有不完善不嚴謹地地方,或者大家有更好的方法,也歡迎在評論區指出,感謝閱讀。?
如果這篇文章能給你帶來一些積極的影響,希望各位能給我點贊收藏 or Github Star(卑微?),再次感謝大家。