Read me
Designed for vue 3, do the same work like vue-class-component and vue-property-decorator.
- Community desired vue class component with typescript decorators.
- Safety. Transform es class to vue option api according to specifications.
- Performance. Once transform on project loading, ready for everywhere.
- Support both es class inherit and vue component extending.
Welcome to suggest and contribute. Message me on github.
Install
npm install -S vue-facing-decorator
How to use
Index
Basic
import {
Component,
Ref,
Watch,
Prop,
Inject,
Emit,
Base,
} from "vue-facing-decorator";
import AnotherComponent from "./AnotherComponent.vue";
class Sup extends Base {
supProperty = "supProperty";
supMethod() {}
get supGetter() {
return "supGetter";
}
}
@Component({
name: "MyComponent",
emits: ["update:modelValue"],
provide: {
provideKey: "provideValue",
},
components: {
AnotherComponent,
},
inheritAttrs:true,
expose:[],
directives:{
},
options: {
beforeRouteEnter() {
},
},
modifier: (option: any) => {
console.log("generated optoin", option);
option.methods ??= {};
option.methods.method2 = function () {
console.log("method2");
};
return option;
},
})
export default class Comp extends Sup {
@Emit()
eventName(arg: any) {
return arg;
}
@Emit("eventCustomNamePromise")
event2(arg: any) {
return new Promise((resolver) => {
resolver(arg);
});
}
@Ref
readonly ref!: HTMLDivElement;
@Prop({
required: true,
default: "default prop",
type: String,
validator(v: string) {
console.log("prop validator", v);
return true;
},
})
readonly prop!: string;
@Prop({
required: true,
type: Number,
})
readonly modelValue!: number;
property = "property";
get getter() {
return "getter";
}
method() {
this.$forceUpdate();
this.property += ">";
this.$emit("update:modelValue", this.modelValue + 1);
}
@Watch("property", {
deep: true,
immediate: true,
flush: "post",
})
propertyWatcher(newv: string, oldv: string) {
console.log("property changed", newv, oldv);
}
@Inject({
default: "defult value",
from: "provideAcientKey",
})
provideAcientKeyAlias!: string;
mounted() {
console.log(
this.ref,
this.getter,
this.property,
this.supProperty,
this.supGetter,
this.prop,
this.provideAcientKeyAlias
);
this.eventName("eventName value");
this.event2("eventCustomNamePromise value");
}
}
is equal to
import { defineComponent} from "vue";
import AnotherComponent from "./AnotherComponent.vue";
export default defineComponent({
name: "MyComponent",
components: {
AnotherComponent,
},
emits: ["update:modelValue", "eventName", "eventCustomNamePromise"],
provide: {
provideKey: "provideValue",
},
inject: {
provideAcientKeyAlias: {
default: "defult value",
from: "provideAcientKey",
},
},
data() {
return {
supProperty: "supProperty",
property: "property",
};
},
methods: {
supMethod() {},
method() {
this.$forceUpdate();
this.$emit("update:modelValue", this.modelValue + 1);
},
method2() {
console.log("method2");
},
eventName() {
this.$emit("eventName", "eventName value");
},
async event2() {
const value = await new Promise<any>((resolver) => {
resolver("eventCustomNamePromise value");
});
this.$emit("eventCustomNamePromise", value);
},
},
watch: {
property: function (newv: string, oldv: string) {
console.log("property changed", newv, oldv);
},
},
computed: {
supGetter() {
return "supGetter";
},
getter() {
return "getter";
},
ref() {
this.$refs["ref"];
},
},
props: {
prop: {
required: true,
default: "default prop",
type: String,
validator: function (v: string) {
console.log("prop validator", v);
return true;
} as any,
},
modelValue: { type: Number, required: true },
},
mounted() {
console.log(
this.ref,
this.property,
this.supProperty,
this.getter,
this.supGetter,
this.prop,
(this as any).provideAcientKeyAlias
);
},
beforeRouteEnter() {},
});
Extends
import { Component, ComponentBase, Base } from 'vue-facing-decorator'
class Comp1Sup extends Base {
method1Sup() {
return 'method1Sup value'
}
}
@ComponentBase
class Comp1 extends Comp1Sup {
method1Comp() {
return 'method1Comp value'
}
}
class Comp2Sup extends Comp1 {
method2Sup() {
return 'method2Sup value'
}
}
@ComponentBase
class Comp2 extends Comp2Sup {
method2Comp() {
return 'method2Comp value'
}
}
class Comp3Sup extends Comp2 {
method3Sup() {
return 'method3Sup value'
}
}
@Component
export default class Comp3 extends Comp3Sup {
method3Comp() {
return 'method3Comp value'
}
}
is euqal to
import { defineComponent } from 'vue';
export default defineComponent({
extends: {
extends: {
methods: {
method1Comp() {
return 'method1Comp value'
}
}
},
methods: {
method2Comp() {
return 'method2Comp value'
}
}
},
methods: {
method3Comp() {
return 'method3Comp value'
}
}
})
Tsx render
import type Comp from './Comp'
export default function render(this: Comp) {
return <div onClick={this.onClick}>Tsx render {this.number}</div>
}
import {
Component,
Base,
} from 'vue-facing-decorator'
import render from './Comp.render'
@Component({
render
})
export default class Comp extends Base {
number = 1
onClick() {
this.number++
}
}
import {
Component,
Base,
} from 'vue-facing-decorator';
import Comp from "./Comp"
@Component({
components:{
Comp
}
})
export default class ParentComponent extends Base {
}
is euqal to
import { defineComponent } from "vue";
import render from './Comp.render'
export default defineComponent({
render,
data(){
return {
number:1
}
},
methods:{
onClick(){
this.number++
}
}
})
In class lifecycle names
These class names could be defined in class directly.
[
"beforeCreate",
"created",
"beforeMount",
"mounted",
"beforeUpdate",
"updated",
"activated",
"deactivated",
"beforeDestroy",
"beforeUnmount",
"destroyed",
"unmounted",
"renderTracked",
"renderTriggered",
"errorCaptured",
"serverPrefetch"
]
For names not in this list, use
@Component({
options:{
foo(){
}
}
})
or
@Component({
modifier(opt:any){
opt.foo=function(){}
return opt
}
})