Skip to content

Use class style to write setup and support vue2 and vue3

License

Notifications You must be signed in to change notification settings

dp-os/vue-class-setup

Repository files navigation

vue-class-setup

Build Status Coverage Status npm npm npm

Why?

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

Install

npm install vue-class-setup
# or
yarn add vue-class-setup

Quick start

<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>

PassOnTo

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) => {
                // ...
            }
        );
    }
}

Define

If the component defines props, writing the class in the setup will cause the setup function to create a class every time as it executes, which will add costs. So we should avoid writing class in setup and use Define basic class to receive props and emit.

The following examples provide best practices

<script lang="ts">
import { Setup, Define } from 'vue-class-setup'

// Pass in 'Props' and 'Emits' through generics, and all props objects are read-only
@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>

// Props and Emits need to be exported
export interface Props { value: number }

export interface Emits {
    (event: 'click', evt: MouseEvent): void;
}

// Variable reception must be used, otherwise Vue compilation error
const props = defineProps<Props>();
const emit = defineEmits<Emits>();

// When creating an app, pass parameters props and emit
const app = new App(props, emit);

</script>
<template>
    <button class="btn" @click="app.click($event)">
        <span class="text">{{ app.text }}</span>
    </button>
</template>