Vue.js 3 Cookbook
上QQ阅读APP看书,第一时间看更新

Creating a custom function decorator with vue-class-component

Decorators were introduced in ECMAScript 2015. A decorator is a kind of high-order function that wraps a function with another function.

This brings a lot of new improvements to the code—along with greater productivity—because it takes the principle of functional programming and simplifies it.

Getting ready

The pre-requisite for this recipe is as follows:

  • Node.js 12+

The Node.js global objects that are required are as follows:

  • @vue/cli
  • @vue/cli-service-global

How to do it...

First, we need to create our Vue CLI project. To find how to create a Vue CLI project, please check the 'Creating your first project with Vue CLI' recipe. We can use the one we created in the last recipe or start a new one.

Follow these steps to create your custom function decorator with vue-class-component:

  1. Create a file called componentMount.js inside the src/decorators folder.
  2. We need to import the createDecorator function from the vue-class-component to be able to use it on a vue-class-component based component, and to start coding our decorator:
import { createDecorator } from 'vue-class-component';
import componentMountLogger from './componentLogger';

export default createDecorator((options) => {
options.mixins = [...options.mixins, componentMountLogger];
});
createDecorator function is like an extension of the Vue vm (View-Model), so it won't have the property of an ECMAScript decorator but will function as a Vue decorator.
  1. We need to use the componentLogger.js file in our decorator. This function will take all the data values that are set in the "decorated" component and add a watcher to it. This watcher will log the new and old values whenever it changes. This function will only be executed with a debug data set to true:
export default {
mounted() {
if (this.debug) {
const componentName = this.name || '';
console.log(`The ${componentName} was mounted
successfully.`);

const dataKeys = Object.keys(this.$data);

if (dataKeys.length) {
console.log('The base data are:');
console.table(dataKeys);

dataKeys.forEach((key) => {
this.$watch(key, (newValue, oldValue) => {
console.log(`The new value for ${key} is:
${newValue}`);
console.log(`The old value for ${key} is:
${oldValue}`);
}, {
deep: true,
});
});
}
}
},
};
  1. Now, we need to import the decorator to our Counter.vue component file located in the src/components folder and add the debugger data to it:
<template>
<div>
<fieldset>
<legend>{{ this.formattedNumber }}</legend>
<button @click="increase">Increase</button>
<button@click="decrease">Decrease</button>
</fieldset>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import componentMount from '../decorators/componentMount';

@Component
@componentMount
export default class Counter extends Vue {
valueNumber: number = 0;

debug: boolean = true;

get formattedNumber() {
return `Your total number is: ${this.valueNumber}`;
}

increase() {
this.valueNumber += 1;
}

decrease() {
this.valueNumber -= 1;
}
}
</script>

How it works...

The createDecorator function is a factory function that extends the Vue vm (View Model), which produces an extension of the Vue component, such as a Vue mixin. A Vue mixin is a property of the Vue component that can be used to share and reuse code between components.

When we call the mixin, it takes the current component as an option of the first argument (the key if it was attached to a property), and the index of it.

We added a dynamic debugger that is only attached when debug data exists and is set to true. This debugger will log the current data and set watchers for the changes in the data, showing the logs on the console each time the data is changed.

There's more...

When using linters, some rules can be a problem with decorators. So, it's wise to disable them only on the files that are having problems with the rules that are required for the code to work.

In an AirBnB style, for example, the no-param-reassign rule is required because the decorator uses the option as a reference to pass the value.

See also

Find more information about creating custom decorators with vue-class-component at https://github.com/vuejs/vue-class-component#create-custom-decorators.

Find more information about decorators on ECMAScript at https://www.typescriptlang.org/docs/handbook/decorators.html.