基础api官方文档

简单来说,ts属于强类型语言,它的优势在于静态类型检查,概括来说主要包括以下几点:

  • 静态类型检查
  • IDE 智能提示
  • 代码重构
  • 可读性

typescript在vue项目中的基础用法

vue-property-decorator

vue-property-decoratorvue-class-component的基础上增加了更多与Vue相关的装饰器,使Vue组件更好的跟TS结合使用。这两者都是离不开装饰器的,(decorator)装饰器已在ES提案中。Decorator是装饰器模式的实践。装饰器模式呢,它是继承关系的一个替代方案。动态地给对象添加额外的职责。在不改变接口的前提下,增强类的性能。

vue-property-decorator是这个Vue项目文件中完全依赖的库,它是Vue官方推荐的并且依赖于vue-class-component,先介绍下它在项目中的常见用法。

@Component 类装饰器

首先,Vue页面中的script部分要加一个lang=ts,这样安装好typescript正能引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script lang="ts">
import {Vue, Component} from 'vue-property-decorator';
import BaseHeader from '@/components/BaseHeader';

//公共头部组件
@Component({
components: {
BaseHeader
}
})
export default class extends Vue {
private stateA:boolean = true
private stateB:string = ''
private stateC:number = 0
private stateD:any = {}
stateE:any[] = []
}
</script>

等同于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
import Vue from 'vue';
import BaseHeader from '@/components/BaseHeader'; //公共头部组件

export default {
components: {
BaseHeader
},

data(){
return {
stateA: true,
stateB: '',
stateC: 0,
stateD: {},
stateE: []
}
}
}
</script>

vue-property-decorator在项目中的应用最主要是起一个装饰器的作用,差异化的话看对比就非常直观了

data变量的定义比较多元化,这里区别有加private,不加就是public,当变量标记为private时,它就不能在声明它的类的外部访问。

@Component装饰器属性名必须得写上


@Prop

父子组件之间的属性传值

1
2
3
4
5
6
7
export default class extends Vue {
@Prop({ default: 0 }) private propA!: number
@Prop({ default: () => [10, 20, 30, 50] }) private propB!: number[]
@Prop({ default: 'total, sizes, prev, pager, next, jumper' }) private propC!: string
@Prop({ default: true }) private propD!: boolean,
@prop([String, Boolean]) propE: string | boolean;
}

等同于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export default {
props: {
propA: {
type: Number
},
propB: {
type: Array,
default: [10, 20, 30, 50]
},
propC: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
propD: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
propE: {
type: [String, Boolean]
}
}
}

这里有两个常用修饰符! ?!和可选参数?是相对的, !表示强制解析(也就是告诉typescript编译器,我这里一定有值),你写?的时候再调用,typescript会提示可能为undefined


@Emit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Component
export default class YourComponent extends Vue {
count = 0

@Emit('reset')
resetCount() {
this.count = 0
}

@Emit()
returnValue() {
return 10
}

@Emit()
onInputChange(e) {
return e.target.value
}
}

等同于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export default {
data() {
return {
count: 0
}
},

methods: {
resetCount() {
this.count = 0
this.$emit('reset')
},

returnValue() {
this.$emit('return-value', 10)
},

onInputChange(e) {
this.$emit('on-input-change', e.target.value, e)
}
}
}

@Emit装饰器的函数会在运行之后触发等同于其函数名(驼峰式会转为横杠式写法)的事件, 并将其函数传递给$emit

@Emit触发事件有两种写法

  • @Emit()不传参数,那么它触发的事件名就是它所修饰的函数名.
  • @Emit(name: string),里面传递一个字符串,该字符串为要触发的事件名

@Watch 观察属性装饰器

@Watch装饰器主要用于替代Vue属性中的watch属性,监听依赖的变量值变化而做一系列的操作

1
2
3
4
5
6
7
8
@Component
export default class YourComponent extends Vue {
@Watch('child')
onChildChanged(val: string, oldVal: string) {}

@Watch('person', { immediate: true, deep: true })
onPersonChanged(val: Person, oldVal: Person) {}
}

等同于

1
2
3
4
5
6
7
8
9
10
export default {
watch: {
child(val, oldVal) {},
person: {
handler(val, oldVal) {},
immediate: true,
deep: true
}
}
}

watch 是一个对象,对象就有键,有值。

  • 第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。
  • 第二个是deep:其值是true或false;确认是否深入监听。deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器(受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除)
  • 第三个是immediate:其值是true或false;immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行

@Watch使用非常简单,接受第一个参数为要监听的属性名, 第二个属性为可选对象。@Watch所装饰的函数即监听到属性变化之后应该执行的函数。

@Watch装饰的函数的函数名并非如上onStateChanged严格命名,它是多元化的,你可以随心所欲的命名,当然,能按照规范化的命名会使你的代码阅读性更好。


@Minxins

1
2
3
4
5
6
// myMixin.ts

@Component
export default class MyMixin extends Vue {
mixinValue:string = 'Hello World!!!'
}
1
2
3
4
5
6
7
8
9
// 引用mixins
import MyMixin from './myMixin.js'

@Component
export default class extends mixins(MyMixin) {
created () {
console.log(this.mixinValue) // -> Hello World!!!
}
}

另外一种mixins写法

先改造一下myMixin.ts,定义vue/type/vue模块,实现Vue接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// myMixin.ts
import { Vue, Component } from 'vue-property-decorator';


declare module 'vue/types/vue' {
interface Vue {
mixinValue: string;
}
}

@Component
export default class myMixins extends Vue {
mixinValue: string = 'Hello World!!!'
}

引用

1
2
3
4
5
6
7
8
9
10
11
import { Vue, Component, Prop } from 'vue-property-decorator';
import MyMixin from './myMixin.js'

@Component({
mixins: [MyMixin]
})
export default class extends Vue{
created(){
console.log(mixinValue) // => Hello World!!!
}
}

两种方式不同在于定义mixins时如果没有定义vue/type/vue模块, 那么在混入的时候就要继承该mixins; 如果定义vue/type/vue模块,在混入时可以在@Componentmixins直接混入。


@Model

@Model装饰器允许我们在一个组件上自定义v-model,接收两个参数:

  • event: string 事件名。
  • options: Constructor | Constructor[] | PropOptions 与@Prop的第一个参数一致。
1
2
3
4
5
6
import { Vue, Component, Model } from 'vue-property-decorator'

@Component
export default class MyInput extends Vue {
@Model('change', { type: String, default: 'Hello world!!!' }) readonly value!: string
}

等同于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<input
type="text"
:value="value"
@change="$emit('change', $event.target.value)"
/>
</template>

export default {
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
type: String,
default: 'Hello world!!!'
}
}
}

@Provide @Inject

@Provide 声明一个值 , 在其他地方用 @Inject 接收,在实战项目中用得不多,一般用于不依赖于任何第三方状态管理库(如vuex)的组件编写


@Ref(refKey?: string)

@Ref装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Vue, Component, Ref } from 'vue-property-decorator'
import { Form } from 'element-ui'

@Componentexport default class MyComponent extends Vue {
@Ref() readonly loginForm!: Form
@Ref('changePasswordForm') readonly passwordForm!: Form

public handleLogin() {
this.loginForm.validate(valide => {
if (valide) {
// login...
} else {
// error tips
}
})
}
}

等同于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default {
computed: {
loginForm: {
cache: false,
get() {
return this.$refs.loginForm
}
},
passwordForm: {
cache: false,
get() {
return this.$refs.changePasswordForm
}
}
}
}

使用时切记要引入修饰器

1
2
3
4
5
6
7
8
9
10
11
12
import {
Vue,
Component,
Prop,
Component,
Emit,
Provice,
Inject,
Watch,
Model,
Minxins,
} from 'vue-property-decorator'

钩子函数

以下的public、private在引入tslint后是必写的,否则会有警告,如果没有引的话是可以不写的

Ts Js 说明
public created() {} created() {} 初始化
public mounted() {} mounted() {} 挂载完毕
private _getInitData() {} methods: { _getInitData() {} } 方法
private get _userName() {} computed: { _userName() {} } 计算属性
public destroyed() {} destroyed() {} 销毁生命周期