vue-property-decorator
为什么要使用 vue-property-decorator
vue-property-decorator 是在 vue-class-component 的基础上做了进一步的封装,在 TypeScript 官方文档 中,官方推荐了 vue-class-component,提供了 Vue,Component 等,而 vue-property-decorator 是社区出品,深度依赖于 vue-class-component,提供了更多操作符:@Component,@Prop,@Watch,@Emit 等等
安装
npm i -S vue-class-component
npm i -S vue-property-decorator
用法
这里有几个装饰器和一个函数(Mixin):
@Prop
@PropSync
@Model
@ModelSync
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
@VModel
@Component (由 vue-class-component 提供)
Mixins (mixins 函数 由 vue-class-component 提供)
@Component
@Component(options:ComponentOptions = {})
即使没有组件也不能省略@Component,否则会报错。
@Component:注明此类为一个 vue 组件
export default class extends Vue: export 当前组件类是继承 vue 的
@Component 装饰器可以接收一个对象作为参数,可以在对象中声明 components ,filters,directives 等未提供装饰器的选项,也可以声明 computed,watch 等
import { Vue, Component } from "vue-property-decorator";
@Component({
filters: {
toFixed: (num: number, fix: number = 2) => {
return num.toFixed(fix);
},
},
})
export default class MyComponent extends Vue {
public list: number[] = [0, 1, 2, 3, 4];
get evenList() {
return this.list.filter((item: number) => item % 2 === 0);
}
}
组件引用
import { Vue, Component } from "vue-property-decorator";
import TestComponent "@/TestComponent.vue";
@Component({
components: {
TestComponent
}
})
export default class ComponentName extends Vue {}
@Prop
- @Prop(options: (PropOptions | Constructor[] | Constructor) = {})
@Prop 装饰器接收一个参数,这个参数可以有三种写法:
- Constructor,例如 String,Number,Boolean 等,指定 prop 的类型;
- Constructor[],指定 prop 的可选类型;
- PropOptions,可以使用以下选项:type,default,required,validator。
注:
- 属性的 ts 类型后面需要加上 undefined 类型;或者在属性名后面加上!,表示非 null 和 非 undefined 的断言,否则编译器会给出错误提示;
- 指定默认值必须使用上面例子中的写法,如果直接在属性名后面赋值,会重写这个属性,并且会报错。
import { Vue, Component, Prop } from "vue-property-decorator";
@Component
export default class ComponentName extends Vue {
@Prop(String) public propA: string | undefined;
@Prop([String, Number]) public propB!: string | number;
@Prop({
type: String,
default: "abc",
})
public propC!: string;
}
@PropSync
- @PropSync(propName: string, options: (PropOptions | Constructor[] | Constructor) = {})
@PropSync 装饰器与@prop 用法类似,二者的区别在于:
- @PropSync 装饰器接收两个参数: propName: string 表示父组件传递过来的属性名; options: Constructor | Constructor[] | PropOptions 与@Prop 的第一个参数一致;
- @PropSync 会生成一个新的计算属性。
注:
- @PropSync 需要配合父组件的.sync 修饰符使用
import { Vue, Component, PropSync } from "vue-property-decorator";
@Component
export default class ComponentName extends Vue {
@PropSync("propA", { type: String, default: "abc" })
public syncedPropA!: string;
}
<template>
<DEMO :like.sync="like" />
</template>
@Model
- @Model(event?: string, options: (PropOptions | Constructor[] | Constructor) = {})
@Model 装饰器允许我们在一个组件上自定义 v-model,接收两个参数:
- event: string 事件名。
- options: Constructor | Constructor[] | PropOptions 与@Prop 的第一个参数一致。
import { Vue, Component, Model } from "vue-property-decorator";
@Component
export default class MyInput extends Vue {
@Model("change", { type: String, default: "123" }) public value!: string;
}
@Watch
- @Watch(path: string, options: WatchOptions = {})
@Watch 装饰器接收两个参数:
- path: string 被侦听的属性名;
- options?: WatchOptions={} options 可以包含两个属性 : immediate?:boolean 侦听开始之后是否立即调用该回调函数; deep?:boolean 被侦听的对象的属性被改变时,是否调用该回调函数;
import { Vue, Component, Watch } from "vue-property-decorator";
@Component
export default class MyInput extends Vue {
@Watch("msg")
public onMsgChanged(newValue: string, oldValue: string) {}
@Watch("arr", { immediate: true, deep: true })
public onArrChanged1(newValue: number[], oldValue: number[]) {}
@Watch("arr")
public onArrChanged2(newValue: number[], oldValue: number[]) {}
}
@Emit
@Emit 装饰器接收一个可选参数,该参数是$Emit的第一个参数,充当事件名。如果没有提供这个参数,$Emit 会将回调函数名的 camelCase 转为 kebab-case,并将其作为事件名;
@Emit 会将回调函数的返回值作为第二个参数,如果返回值是一个 Promise 对象,$emit 会在 Promise 对象被标记为 resolved 之后触发;
@Emit 的回调函数的参数,会放在其返回值之后,一起被$emit 当做参数使用。
如果事件的名称未通过事件参数提供,则使用函数名称。 在这种情况下,camelCase 名称将转换为 kebab-case。
import { Vue, Component, Emit } from "vue-property-decorator";
@Component
export default class ComponentName extends Vue {
count = 0;
@Emit()
addToCount(n: number) {
this.count += n;
}
@Emit("reset")
resetCount() {
this.count = 0;
}
@Emit()
returnValue() {
return 10;
}
@Emit()
promise() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(20);
}, 0);
});
}
}
@Ref
@Ref(refKey?: string)
@Ref 装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数
import { Vue, Component, Ref } from "vue-property-decorator";
import AnotherComponent from "@/path/to/another-component.vue";
@Component
export default class YourComponent extends Vue {
@Ref() readonly anotherComponent!: AnotherComponent;
@Ref("aButton") readonly button!: HTMLButtonElement;
}
等同于
export default {
computed() {
anotherComponent: {
cache: false,
get() {
return this.$refs.anotherComponent as AnotherComponent
}
},
button: {
cache: false,
get() {
return this.$refs.aButton as HTMLButtonElement
}
}
}
}
Mixins 用法
- 定义 mixins 文件
import { Vue, Component } from "vue-property-decorator";
@Component
export default class testMixins extends Vue {
test: string = "测试数据";
}
- 使用
import { Component, Vue } from "vue-property-decorator";
import outMixins from "./mixins";
@Component({
mixins: [outMixins],
})
export default class ComponentName extends Vue {}