vue-class-api

0.0.5 • Public • Published

Vue 3 Class API

While we recognize the decision by the team behind Vue 3 to drop support for Class Components we decided to give it another shot.

API Documentation

@Component

Similar to vue-class-components every component is defined as:

<template>
	<div>My Component</div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-class-api';

@Component(options: ComponentOptions)
export default class MyComponent extends Vue {}
</script>

ComponentOptions is an object with the same pattern used in the Options API (if there's any part of the Options API implementation that hasn't been covered yet in the Class API implementation).

Computed Properties

All getter/setters are automatically transformed into computed properties.

@Prop

import { Vue, Component, Prop } from 'vue-class-api';

@Component()
export default class MyComponent extends Vue {
	@Prop({ type : Number, default : 3 })
	readonly foo: number;

	@Prop({ required : true })
	readonly bar: number;

	@Prop()
	readonly lorem: number;
}

Prop takes one argument that is identical what would normally be supplied to the props object in the Options API.

@Ref

Simplifies accessing template refs by moving them to the instance's scope.

<template>
	<div>My Component</div>
	<MyOtherComponent ref="foo"></MyOtherComponent>
</template>

<script lang="ts">
import { Vue, Component }    from 'vue-class-api';
import MyOtherComponent from './foo/MyOtherComponent.vue'

@Component({ 
	components : { MyOtherComponent }
})
export default class MyComponent extends Vue {
	@Ref()
	foo: MyOtherComponent;

	// assuming `MyOtherComponent` has exposed a method called `poke()`
	pokeFoo() {
		this.foo.poke(); // identical to this.$refs.foo.poke();
	}
}
</script>

@Expose

Once used, only the decorated fields would be available to the parent component when referenced using the ref attribute.

import { Vue, Component, Expose } from 'vue-class-api';

@Component()
export default class MyComponent extends Vue {

	@Expose()
	foo() {
		console.log('Called foo');
	}

	// Not accessible if this component is referenced by parent
	hiddenFunction() {
		console.log('Boo!');
	}

}

@Emits

Populated the emits field in the Options API which helps with better documentation of the component.

import { Vue, Component, Emits } from 'vue-class-api';

@Component()
export default class MyComponent extends Vue {

	isCool = false;

	// List out any potential emits from the method
	@Emits('bob', 'marley')
	foo() {
		if (this.isCool) {
			this.$emit('bob');
		}
		else {
			this.$emit('marley');
		}
		this.$emit('bob');
		console.log('Called foo');
	}

	@Emits('jack', 'bob')
	bar() {
		this.$emit('jack');
		this.$emit('bob');
		console.log('Boo!');
	}

}

Above will produce:

{
	emits : [ 'bob', 'marley', 'jack' ],
}

@Watch

Example:

import { Vue, Component, Watch } from 'vue-class-api';

@Component()
export default class MyComponent extends Vue {

	spaghetti = {
		delicious : true,
	}

	@Watch('spaghetti', { deep : true, immediate : false })
	foo() {
		console.log('Somebody touched my spaghetti!');
	}

	mounted() {
		this.spaghetti.delicious = false;
	}

}

@Provide/@Inject

import { Vue, Component, Provide } from 'vue-class-api';

@Component({ components : MyChildComponent })
export default class MyComponent extends Vue {
	@Provide('food')
	food: number = 123;
}
import { Vue, Component, Inject } from 'vue-class-api';

@Component()
export default class MyChildComponent extends Vue {
	@Inject('food')
	bar: number;

	mounted () {
		console.log(this.bar === 123); // true
	}
}

Objects are also supported, however they are being wrapped in a computed function provided by Composition API. The reactivity behavior is subject to change depending on how computed changes.

@Hook

Lifecycle hooks are available in two forms:

  1. Hook decorator around any method which exposes method in the methods object and also gets used as a lifecycle hook
  2. Special method names defined on the class
import { Vue, Component, Hook } from 'vue-class-api';

@Component()
export default class MyComponent extends Vue {

	@Hook('mounted')
	foo() {
		console.log('This will run second.');
	}

	// Since the name of the method is one of the lifecycle hooks it gets picked up as a life cycle hook 
	mounted() {
		console.log('This will run first.');
	}

	@Hook('beforeMount')
	bar() {
		console.log('This will run before everything else');
	}

	@Hook('mounted')
	foo2() {
		console.log('You can have more than one mounted hook so long as the method is decorated with the same hook name');
		console.log('This will run after foo()'); // While not guaranteed, in most of the cases, the order of decorator execution is top->bottom
	}

}

Mixin

In order to create nested Vue Components you can use the Mixin helper function like so:

import { Vue, Component, Mixin } from 'vue-class-api';

@Component()
export default class Mom extends Vue {
	mounted() {
		console.log('Dad');
	}
}

@Component()
export default class Dad extends Vue {
	mounted() {
		console.log('Mom');
	}
}

@Component()
export default class Child extends Mixin(Mom, Dad) {
	mounted() {
		console.log('Child');
	}
}

The order of mounted hooks running would be like so:

Mom
Dad
Child

While this is not a temporary solution and here to stay, we are working on a better solution for component inheritance with a more robust development flow.

Roadmap

  1. Extending Components: We're working on a better solution for nested components that provides full typescript support.
  2. More Quality-of-Life Decorators: We're trying to isolate component options into their own standalone decorators. The end goal is to not have a need to provide any arguments to the @Component decorator.

Contributions

If you have a proposal for a new decorator to simplify the component definition process or some new cool feature you recently stumbled upon, open up a pull-request. All ideas are welcome!

License

                GNU GENERAL PUBLIC LICENSE
                   Version 3, 29 June 2007

Copyright (C) 2007 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

Dependencies (3)

Dev Dependencies (10)

Package Sidebar

Install

npm i vue-class-api

Weekly Downloads

3

Version

0.0.5

License

GPL-3.0-or-later

Unpacked Size

61.8 kB

Total Files

8

Last publish

Collaborators

  • darrenrahnemoon