Creating a custom mixin with vue-class-component
In Vue, a mixin is a way to reuse the same code in other Vue objects, like mixing all the property of the mixin inside the component.
When using a mixin, Vue first declares the mixin property and then the component values, so the components will be always the last and valid values. This merge occurs in a deep mode and has a specific way already declared inside the framework, but it can be changed by a special config.
With the use of mixins, developers can write tiny pieces of code and reuse them in lots of components.
This approach simplifies your work and allows you to complete tasks quicker.
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. We can use the one we created in the last recipe or start a new one. To find how to create a Vue CLI project with TypeScript, please check the 'Creating your first TypeScript Vue component with vue-class-component' recipe.
In this recipe, we will split it into two separate parts. First, we will create the counter component, and then we will use the code that is shared to create the mixin.
Creating the Counter component
Now, follow the instructions to create a custom mixin with vue-class-component:
- We need to make a new component called CounterByTen.vue in the src/components folder.
- Now, let's start making the script part of the Vue component. We will make a class that will have a variable with the type of a number and a default value of 0; two methods, one for increasing by 10 and another for decreasing by 10; and, finally, a computed property to format the final data:
<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class CounterByTen extends Vue {
valueNumber: number = 0;
get formattedNumber() {
return `Your total number is: ${this.valueNumber}`;
}
increase() {
this.valueNumber += 10;
}
decrease() {
this.valueNumber -= 10;
}
}
</script>
- It's time to create the template and rendering for this component. The process is the same as for a JavaScript Vue file. We will add the buttons for increasing and decreasing the value and for showing the formatted text:
<template>
<div>
<fieldset>
<legend>{{ this.formattedNumber }}</legend>
<button @click="increase">Increase By Ten</button>
<button @click="decrease">Decrease By Ten</button>
</fieldset>
</div>
</template>
- In the App.vue file, we need to import the component we just created:
<template>
<div id="app">
<Counter />
<hr />
<CounterByTen />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Counter from './components/Counter.vue';
import CounterByTen from './components/CounterByTen.vue';
@Component({
components: {
Counter,
CounterByTen,
},
})
export default class App extends Vue {
}
</script>
<style lang="stylus">
#app
font-family 'Avenir', Helvetica, Arial, sans-serif
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
text-align center
color #2c3e50
margin-top 60px
</style>
Extracting similar code for the mixin
With both of the components having similar code, we can extract this similar code and create a mixin. This mixin can be imported in both of the components and their behavior will be the same:
- Create a file called defaultNumber.ts in the src/mixins folder.
- To code our mixin, we will import the Component and Vue decorators from the vue-class-component plugin, to be the base of the mixin. We will need to take a similar code and place it inside the mixin:
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class DefaultNumber extends Vue {
valueNumber: number = 0;
get formattedNumber() {
return `Your total number is: ${this.valueNumber}`;
}
}
- With the mixin ready, open the Counter.vue component on the src/components folder and import it. To do this, we need to import a special export from the vue-class-component called mixins and extend it with the mixin we want to extend. This will remove the Vue and Component decorators because they are already declared on the mixin:
<template>
<div>
<fieldset>
<legend>{{ this.formattedNumber }}</legend>
<button @click="increase">Increase By Ten</button>
<button @click="decrease">Decrease By Ten</button>
</fieldset>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import Component, { mixins } from 'vue-class-component';
import DefaultNumber from '../mixins/defaultNumber';
@Component
export default class CounterByTen extends mixins(DefaultNumber) {
increase() {
this.valueNumber += 10;
}
decrease() {
this.valueNumber -= 10;
}
}
</script>
- Now, when you run the npm run serve command on Terminal (macOS or Linux) or Command Prompt/PowerShell (Windows), you will see your component running and executing on screen:
How it works...
The process of using mixins with TypeScript is the same as with the Vue objects. The code that is shared can be split into smaller files and called in the components for easier coding.
When using TypeScript and vue-class-component, the Vue and Component decorators need to be declared on the mixins because the class that will be using the mixin will already have this extension, as it extends this mixin.
We took the same piece of code that works the same on both the components and placed it in a new file that is then called in both of the components.
See also
Find more about vue-class-component mixins at https://github.com/vuejs/vue-class-component#using-mixins.
Find more about Vue mixins at https://v3.vuejs.org/guide/mixins.html