Using class can help you avoid ref
, reactive
and computed
, and significantly reduce your mental burden and better organize your code. It supports vue2 and vue3 at the same time. After gzip compression, it is only 1KB
npm install vue-class-setup
# or
yarn add vue-class-setup
<script lang="ts">
import { onMounted } from 'vue';
import { Setup, PassOnTo } from 'vue-class-setup';
@Setup
class Count {
public value = 0;
public get text() {
return String(this.value);
}
public set text(text) {
this.value = Number(text);
}
@PassOnTo(onMounted)
public init() {
this.value++;
}
}
</script>
<script setup lang="ts">
// Use the class you write in setup
const count = new Count();
</script>
<template>
<p>{{ count.text }}</p>
<input type="number" v-model="count.text" />
</template>
This callback
will be called back after the Test class
instantiation is completed, and the decorated function will be passed in, and the TS can check whether the type is correct
class Test {
@PassOnTo(myFunc)
public init(name: string) {}
}
function myFunc (callback: (name: string) => void) {
// ...
}
If PassOnTo
does not pass in a handler, it is called after reactive
and computed
execution are completed, You should avoid watching in the constructor
because it may not have reactive
import { Watch } from 'vue';
@Setup
class Count {
public value = 0;
@PassOnTo()
private setup() {
// Safe Watch
watch(
() => this.value,
(value) => {
// ...
}
);
}
}
If the component defines props
, writing class
in setup
will cause the setup
function to create a class
every time it is executed, which will increase the cost. Therefore, we should avoid writing class
in setup
and use Define
basic class
to receive props
and Emits
. The following example provides a best practice
<script lang="ts">
import { Setup, Define } from 'vue-class-setup'
@Setup
class App extends Define<Props, Emits> {
public get text() {
return String(this.props.value);
}
public click(evt: MouseEvent) {
this.emit('click', evt);
}
}
</script>
<script lang="ts" setup>
export interface Props { value: number }
export interface Emits {
(event: 'click', evt: MouseEvent): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
const app = new App(props, emit);
</script>
<template>
<button class="btn" @click="app.click($event)">
<span class="text">{{ app.text }}</span>
</button>
</template>