前言
近几个月来,关于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(卑微🐶),再次感谢大家。