I am working with a mid size project utilizing Vuejs as the front-end. The options I am exploring to encapsulate / separate the common methods which may be used in many components include mixins approach and plugin approach.
Mixin Approach
I have to write an import statement in each of the component (file) where I want to use the mixin methods. Does this increase the final file size as the mixin will be imported at multiple places? I can use this
within the mixin methods.
Plugin Approach
I can install the plugin globally with Vue.use(MyPlugin)
and use the plugin in any component without importing the plugin in each component.
Drawback: I am not able to use this[field]
within the plugin methods. I have to pass the instance of the calling component vm
to use such methods.
Edit 1 - to include Extend Approach
Extend Approach
I can define a base component with all the methods which will have use in multiple other components and then extend this BaseComponent to create new components. Here again, I need to pass in the instance of the inheriting component , this used in the BaseComponent does not refer to the calling/inheriting component.
Please find the trivial example of code similar to what I am using below:
//mixin.js
var MyMixin = {
methods:{
getName(){
return this.name;
}
}
};
export default MyMixin;
//plugin.js
var MyPlugin = {};
MyPlugin.install = function(Vue, options){
var service = {
getTheName(){
retrun this.name;
},
getTheNameVersion2(vm){ //here vm is the instance of the calling component passed as a parameter - is this proper way?
return vm.name;
}
}
Vue.prototype.$service = service;
};
export default MyPlugin;
//my-component.js
import MyMixin from './mixin';
export default{
template:require('./my-component-template.html'),
mixins:[MyMixin],
data(){
return{
name:'John Doe'
}
},
methods:{
displayNameFromMixin(){
console.log(this.getName()); //displays John Doe - using the mixin method.
},
displayNameFromPlugin(){
console.log(this.$service.getTheName()); //error "this" references the plugin instead of the component instance
},
displayNameFromPluginVersion2(){
console.log(this.$service.getTheNameVersion2(this)); //this works - passing the instance as method parameter
}
}
//base-component.js
export default{
methods:{
getName(vm){
return vm.name;
}
}
}
//another-component.js
import BaseComponent from './base-component';
BaseComponent.extend({
template:require('./another-component-template.html'),
data(){
return{
name:'Jack Daniels';
}
},
methods:{
getNameFromBaseComponent(){
console.log(this.getName(this)); //displays Jack Daniels - instance passed as method parameter
}
}
});
//main.js
import Vue from 'vue';
import MyPlugin from './plugin';
import MyComponent from './my-component';
import AnotherComponent from './another-component';
Vue.use(MyPlugin);
new Vue({
el:'body',
components:{
MyComponent, AnotherComponent
}
});
My questions:
Importing mixin file in every component (which requires the methods)
is it an efficient way of doing it?
Does importing mixin at multiple places (component files) include code of mixin file repeatedly and increase the file size?
Passing the instance of the calling component vm = this
as a parameter - Is it a good practice? Does passing around component
instances as method parameters cause any efficiency issue?
How to bind this (instance of the calling/inheriting component)
to the methods within plugin and/or BaseComponent so that this
refers to the calling/inheriting component instance rather than plugin/BaseComponent?
You can always define a variable outside of the Vue app scope and use it throughout the application. However, if you are using any bundler like Webpack/Browserify/etc. you can do the same but you'd have to import it into every component using it.
Component names should always be multi-word, except for root App components, and built-in components provided by Vue, such as <transition> or <component> . This prevents conflicts with existing and future HTML elements, since all HTML elements are a single word.
what I prefer (someone would consider it not the best way but it is enough for me) is to create plugins.
So I have a file called vue-utils.js with the content (for example):
; (function () {
var install = function(Vue, options) {
Vue.prototype.$utils = {}
var vm = new Vue({ data: Vue.prototype.$utils });
Vue.prototype.$utils.validateEmail = function(value) {
return /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(value);
}
}
if (typeof exports == 'object') {
module.exports = install;
} else if (typeof define == 'function' && define.amd) {
define([], function () { return install });
} else if (window.Vue) {
Vue.use(install);
}
})();
I define the $utils first and then I create a new Vue instance with it so I transform any property to binded, and then define another properties and methods.
Then load it in the app this way:
import VueUtils from './plugins/vue-utils.js';
Vue.use(VueUtils);
And you will be able to reach the component in the HTML like $utils and in the JS by this.$utils
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With