声明文件
使用ts开发时如果要使用第三方js库的同时还想利用ts诸如类型检查等特性就需要声明文件,类似 xx.d.ts
同时,vue项目中还可以在shims-vue.d.ts中对已存在模块进行补充
npm i @types/xxx
//范例:利用模块补充$axios属性到Vue实例,从而在组件里面直接用
// main.ts
import axios from 'axios'
Vue.prototype.$axios = axios;
// shims-vue.d.ts
import Vue from "vue";
import { AxiosInstance } from "axios";
declare module "vue/types/vue" {
interface Vue {
$axios: AxiosInstance;
}
}
范例:给krouter/index.js编写声明文件,index.d.ts
import VueRouter from "vue-router";
declare const router: VueRouter
export default router
装饰器 vue的应用
装饰器用于扩展类或者它的属性和方法。@xxx就是装饰器的写法
# 状态管理推荐使用:vuex-module-decorators
vuex-module-decorators 通过装饰器提供模块化声明vuex模块的方法,可以有效利用ts的类型系统。
#安装
npm i vuex-module-decorators -D
@Prop
原始写法
export default {
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
}
}
@Prop写法
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
@Prop({ type: String, required: true }) readonly title!: string;
@Prop({ type: Number, default: 0 }) readonly count!: number;
}
@Emit
原始
export default {
methods: {
emitSubmit(payload) {
this.$emit('submit', payload);
}
}
}
@Emit写法
import { Component, Vue, Emit } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
@Emit('submit')
emitSubmit(payload: string) {
return payload;
}
}
- 通知父类新增事件,若未指定事件名则函数名作为事件名
- 若没有返回值形参将作为事件参数
- 若有返回值则返回值作为事件参数
@watch
原始
export default {
data() {
return {
message: ''
};
},
watch: {
message(newVal, oldVal) {
console.log(`Message changed from ${oldVal} to ${newVal}`);
}
}
}
@Watch写法
import { Component, Vue, Watch } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
message: string = '';
@Watch('message')
onMessageChanged(newVal: string, oldVal: string) {
console.log(`Message changed from ${oldVal} to ${newVal}`);
}
}
@component
原始
export default {
// 组件逻辑
}
@component
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
// 组件逻辑
mounted() {
//...
}
}
为什么还要继承Vue, 因为TS需要强类型判断,会找不到 mounted等方法报错
Vuex
//根模块清空,修改store/index.ts
export default new Vuex.Store({})
//定义counter模块,创建store/counter.ts
import { Module, VuexModule, Mutation, Action, getModule } from 'vuex-module-decorators'
import store from './index'
// 动态注册模块
@Module({ dynamic: true, store: store, name: 'counter', namespaced: true })
class CounterModule extends VuexModule {
count = 1
@Mutation
add() {
// 通过this直接访问count
this.count++
}
// 定义getters
get doubleCount() {
return this.count * 2;
}
@Action
asyncAdd() {
setTimeout(() => {
// 通过this直接访问add
this.add()
}, 1000);
}
} // 导出模块应该是getModule的结果
export default getModule(CounterModule)
//使用,App.vue
<p @click="add" > {{ $store.state.counter.count }}</p >
<p @click="asyncAdd" > {{ count }}</p >
<script>
import CounterModule from '@/store/counter'
@Component
export default class App extends Vue {
get count() {
return CounterModule.count
} a
dd() {
CounterModule.add()
} a
syncAdd() {
CounterModule.asyncAdd()
}
}
</script>
当然也可以使用vuex-class实现
@Component源码实现
<template >
<div>{{ msg }}</div>
</template >
<script lang='ts'>
import { Vue } from "vue-property-decorator";
function Component(options: any) {
return function(target: any) {
return Vue.extend(options);
};
}
@Component({
props: {
msg: {
type: String,
default: ""
}
}
})
export default class Decor extends Vue {}
</script>