前言
TS的一些用法其实官网介绍的很明白了,只不过如何去使用,在项目中如何搭建,
vue-property-decorator
vue-property-decorator
在vue-class-component
的基础上增加了更多与Vue
相关的装饰器,使Vue
组件更好的跟TS结合使用。这两者都是离不开装饰器的,(decorator)装饰器已在ES提案中。Decorator
是装饰器模式的实践。装饰器模式呢,它是继承关系的一个替代方案。动态地给对象添加额外的职责。在不改变接口的前提下,增强类的性能。
vue-property-decorator
是这个Vue项目文件中完全依赖的库,它是Vue官方推荐的并且依赖于vue-class-component,先介绍下它在项目中的常见用法。
- @Component
- @Emit
- @Provice @Inject
- @Prop
- @Watch
- @Model
- @Minxins
@Component 类装饰器
首先,Vue页面中的script部分要加一个lang=ts,这样安装好typescript正能引用
<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>
等同于
<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
父子组件之间的属性传值
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; }
等同于
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
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 } }
等同于
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
属性,监听依赖的变量值变化而做一系列的操作
@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) {} }
等同于
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
严格命名,它是多元化的,你可以随心所欲的命名,当然,能按照规范化的命名会使你的代码阅读性更好。
// myMixin.ts @Component export default class MyMixin extends Vue { mixinValue:string = 'Hello World!!!' } // 引用mixins import MyMixin from './myMixin.js' @Component export default class extends mixins(MyMixin) { created () { console.log(this.mixinValue) // -> Hello World!!! } }
Minxins
然后我又偷学到了另外一种mixins写法,记录一下
先改造一下myMixin.ts
,定义vue/type/vue
模块,实现Vue接口
// 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!!!' }
引用
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
模块,在混入时可以在@Component
中mixins
直接混入。
@Provide @Inject
@Provide
声明一个值 , 在其他地方用 @Inject
接收,在实战项目中用得不多,一般用于不依赖于任何第三方状态管理库(如vuex)的组件编写
@Ref(refKey?: string)
@Ref
装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数
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 } }) } }
等同于
export default { computed: { loginForm: { cache: false, get() { return this.$refs.loginForm } }, passwordForm: { cache: false, get() { return this.$refs.changePasswordForm } } } }
使用时切记要引入修饰器
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() {} | 销毁生命周期 |