如何在vue2中使用Typescript开发应用程序
Vue
是一个轻量的渐进式前端框架。但是老版本的 Vue
并没有很好的支持 Typescript
。随着官方对 Typescript
的支持,使用 Vue CLI
可以从头开始创建 Typescript
项目。但是仍然需要一些带有自定义装饰器和功能的第三方包来创建一个真正的、完整的 Typescript
应用程序,而官方文档并不包含入门所需要的所有信息。为了帮助大家全面地了解它,我们将演示如何使用 Vue CLI
构建一个新的 Vue + TypeScript
应用程序。
1.基于类的组件
javascript
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
}
</script>
Javascript
等价代码如下:
js
<script>
export default {
name: 'HelloWorld'
}
</script>
引入一个组件
在组件中注册其他组件的代码是在 @Component
装饰器中编写的,如下所示。
javascript
<template>
<div class="main">
<project />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Project from '@/components/Project.vue'
@Component({
components: {
project
}
})
export default class HelloWorld extends Vue {
}
</script>
Javascript
等价代码如下:
js
<template>
<div class="main">
<project />
</div>
</template>
<script>
import Project from '@/components/Project.vue'
export default {
name: 'HelloWorld',
components: {
project
}
})
</script>
2. Data, props, computed 属性, methods, watchers, and emit
使用 data
要使用 data
属性,我们可以简单地将它们声明为类变量。
js
@Component
export default class HelloWorld extends Vue {
private msg: string = "welcome to my app"
private list: Array<object> = [
{
name: 'Preetish',
age: '26'
},
{
name: 'John',
age: '30'
}
]
}
Javascript
等价代码如下:
js
export default {
data() {
return {
msg: "welcome to my app",
list: [
{
name: 'Preetish',
age: '26'
},
{
name: 'John',
age: '30'
}
]
}
}
使用 props
我们可以使用 @Prop
装饰器在 Vue
组件中使用 props
。在 Vue
中,我们可以给额外的配置给 props
,比如 required
、default
和 type
。首先我们可以像下面一样从 vue-property-decorator
引入 Prop
装饰器。我们还可以使用 readonly
去避免操作改变 props
。
js
import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
@Prop() readonly msg!: string
@Prop({default: 'John doe'}) readonly name: string
@Prop({required: true}) readonly age: number
@Prop(String) readonly address: string
@Prop({required: false, type: String, default: 'Developer'}) readonly job: string
}
</script>
Javascript
等价代码如下:
js
props: {
msg,
name: {
default: 'John doe'
},
age: {
required: true,
},
address: {
type: String
},
job: {
required: false,
type: string,
default: 'Developer'
}
}
}
Computed 属性
计算属性用于编写简单的模板逻辑,例如操作、添加或连接数据。在 TypeScript
中,一个普通的计算属性也以 get
关键字作为前缀。
js
export default class HelloWorld extends Vue {
get fullName(): string {
return this.first+ ' '+ this.last
}
}
Javascript
等价代码如下:
js
export default {
fullName() {
return this.first + ' ' + this.last
}
}
在 Typescript
中,我们可以写一些复杂的包括 getter
和 setter
的计算属性,如下所示
js
export default class HelloWorld extends Vue {
get fullName(): string {
return this.first+ ' '+ this.last
}
set fullName(newValue: string) {
let names = newValue.split(' ')
this.first = names[0]
this.last = names[names.length - 1]
}
}
Javascript
等价代码如下:
js
fullName: {
get: function () {
return this.first + ' ' + this.last
},
set: function (newValue) {
let names = newValue.split(' ')
this.first = names[0]
this.last = names[names.length - 1]
}
}
Methods
与普通类方法一样,TypeScript
中的方法也有一个可选的访问修饰符。
js
export default class HelloWorld extends Vue {
public clickMe(): void {
console.log('clicked')
console.log(this.addNum(4, 2))
}
public addNum(num1: number, num2: number): number {
return num1 + num2
}
}
Javascript
等价代码如下:
js
export default {
methods: {
clickMe() {
console.log('clicked')
console.log(this.addNum(4, 2))
}
addNum(num1, num2) {
return num1 + num2
}
}
}
Watchers
最常用的 JavaScript
书写 watcher
的语法如下:
css
watch: {
name: function(newval) {
//do something
}
}
不经常使用 handler
语法
js
watch: {
name: {
handler: 'nameChanged'
}
}
methods: {
nameChanged (newVal) {
// do something
}
}
在 TypeScript
中,我们使用 @Watch
装饰器并传递需要监视的变量的名称。
js
@Watch('name')
nameChanged(newVal: string) {
this.name = newVal
}
也可以使用 immediate
和 deep
js
@Watch('project', {
immediate: true, deep: true
})
projectChanged(newVal: Person, oldVal: Person) {
// do something
}
Javascript
等价代码如下:
js
watch: {
person: {
handler: 'projectChanged',
immediate: true,
deep: true
}
}
methods: {
projectChanged(newVal, oldVal) {
// do something
}
}
Emit
要从一个子组件 emit
一个方法到父组件,在 Typescript
中,我们将使用 @Emit
装饰器。
子组件:
js
@Emit()
addToCount(n: number) {
this.count += n
}
@Emit('resetData')
resetCount() {
this.count = 0
}
父组件:
js
<some-component add-to-count="addToCount" />
<some-component reset-data="resetCount" />
methods: {
addToCount(n) {
this.count += n
this.$emit('add-to-count', n)
},
resetCount() {
this.count = 0
this.$emit('resetData')
}
}
3.生命周期钩子
js
export default class HelloWorld extends Vue {
mounted() {
//do something
}
beforeUpdate() {
// do something
}
}
Javascript
等价代码如下:
js
export default {
mounted() {
//do something
}
beforeUpdate() {
// do something
}
}
4. Mixins
为了在 Typescript
中创建 mixins
,我们必须首先创建 mixin
文件,其中包含我们与其他组件共享的数据。
创建一个名为 ProjectMixin.ts
的文件。在 mixin
目录中添加下面的 mixin
,它共享 projName
和更新 projName
的方法。
js
import { Component, Vue } from 'vue-property-decorator'
@Component
class ProjectMixin extends Vue {
public projName: string = 'My project'
public setProjectName(newVal: string): void {
this.projName = newVal
}
}
export default ProjectMixin
Javascript
等价代码如下:
js
export default {
data() {
return {
projName: 'My project'
}
},
methods: {
setProjectName(newVal) {
this.projName = newVal
}
}
}
在我们的 Vue
组件中使用上面的 mixin
,我们需要从 vue-property-decorator
引入 Mixins
和引入 mixin
文件,如下所示
js
//Projects.vue
<template>
<div class="project-detail">
{{ projectDetail }}
</div>
</template>
<script lang="ts">
import { Component, Vue, Mixins } from 'vue-property-decorator'
import ProjectMixin from '@/mixins/ProjectMixin'
@Component
export default class Project extends Mixins(ProjectMixin) {
get projectDetail(): string {
return this.projName + ' ' + 'Preetish HS'
}
}
</script>
Javascript 等价代码如下:
js
<template>
<div class="project-detail">
{{ projectDetail }}
</div>
</template>
<script>
import ProjectMixin from '@/mixins/ProjectMixin'
export default {
mixins: [ ProjectMixin ],
computed: {
projectDetail() {
return this.projName + ' ' + 'Preetish HS'
}
}
}
</script>
5. Vuex
Vuex
是大多数 Vue.js
应用程序中使用的官方状态管理库。将 store
划分为命名空间模块是一个很好的实践。我们将演示如何在 TypeScript
中编写它。
首先,需要安装两个流行的第三方库:
js
npm install vuex-module-decorators -D
npm install vuex-class -D
在 store文件夹中,让我们创建一个 module
文件夹来放置我们的命名空间存储模块。
创建一个名为 user
的文件。ts
拥有 user
的状态。
js
// store/modules/user.ts
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
@Module({ namespaced: true, name: 'test' })
class User extends VuexModule {
public name: string = ''
@Mutation
public setName(newName: string): void {
this.name = newName
}
@Action
public updateName(newName: string): void {
this.context.commit('setName', newName)
}
}
export default User
Javascript
等价代码如下:
js
export default {
namespaced: true,
state: {
name: ''
},
mutations: {
setName(state, newName) {
state.name = newName
}
},
actions: {
updateName(context, newName) {
context.commit('setName', newName)
}
}
}
在 store
文件夹中,我们需要创建一个 index.ts
去初始化 Vuex
并注册此模块
js
import Vue from 'vue'
import Vuex from 'vuex'
import User from '@/store/modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
User
}
})
export default store
在组件中使用 Vuex
要使用 Vuex
,我们可以利用一个名为 Vuex -class
的库。这个库提供装饰器来绑定 Vue
组件中的 State
, Getter
, Mutation
和 Action
。
因为我们使用的是带有命名空间的 Vuex
模块,所以我们首先从 Vuex
类导入命名空间,然后传递模块的名称来访问该模块。
js
<template>
<div class="details">
<div class="username">User: {{ nameUpperCase }}</div>
<input :value="name" @keydown="updateName($event.target.value)" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { namespace } from 'vuex-class'
const user = namespace('user')
@Component
export default class User extends Vue {
@user.State
public name!: string
@user.Getter
public nameUpperCase!: string
@user.Action
public updateName!: (newName: string) => void
}
</script>
Javascript
等价代码如下:
js
<template>
<div class="details">
<div class="username">User: {{ nameUpperCase }}</div>
<input :value="name" @keydown="updateName($event.target.value)" />
</div>
</template>
<script>
import { mapState, mapGetters, mapActions} from 'vuex'
export default {
computed: {
...mapState('user', ['name']),
...mapGetters('user', ['nameUpperCase'])
}
methods: {
...mapActions('user', ['updateName'])
}
}
</script>