By yugasun from yugasun.com/post/you-ma… This article can be reproduced in full, but the original author and source need to be retained.
We in the actual development process, when a project is more and more big, the component is more and more rich, often face a problem: many components will pay some props, the data and the methods of general statement, but also unique doping component some of his own private statement, so we can’t like class inheritance, to refine and inheritance? This is possible, of course, through two basic apis extends and mixins. The two apis are interchangeable, the only difference being that the extends property usually accepts a single component object, while the mixins property accepts an array of component objects. When they inherit from a single component, they are interchangeable. Since I am used to using mixins in my development, all examples in this article are implemented using mixins.
mixins
Take a look at the official introduction:
The mixins option accepts an array of mixins. These mixin instance objects can contain the same options as normal instance objects, and they will eventually be merged using the same option merge logic in vue.extend (). For example: if your mixin contains a hook and the creation component itself has one, two functions will be called.
The simple understanding is that all attribute configurations in a Vue instance can be inherited through mixins.
A simple example is as follows:
var mixin = {
created: function () { console.log(1)}}var vm = new Vue({
created: function () { console.log(2)},mixins: [mixin]
})
/ / = > 1
/ / = > 2
Copy the code
Case 1
Mounted hook () {/ / add hook () {/ / add hook () {/ / add hook () {/ / add hook () {/ / add hook ();
export default {
name: 'comp1'.// ...
mounted() {
console.log('Component comp1 mounted');
}
// ...
}
Copy the code
Then one day the requirement turned out to be a few components that needed to be addressed. Well, we did another big operation, copying the code above to each of the components that needed to be addressed. But the nightmare is just beginning, after a few days the requirements have changed, in addition to the component rendering need to hit, but also need to hit….. after created This kind of scene is not like love, in the face of reality we always keep yielding, and finally the pain to do the need.
Thinking back calmly, in fact, this point is very common demand. If we had to do it all over again, we would have chosen to inherit rather than blindly love, no, blindly copy and paste. Because we have mixins, we only write them once and they’re available everywhere. SRC /minins/log.js: SRC /minins/log.js
export default {
created() {
console.log(`Component The ${this.$options.name} created.`);
},
mounted() {
console.log(`Component The ${this.$options.name} mounted.`); }};Copy the code
Then use it in any component you need:
import logMixin from '@/mixins/log';
export default {
name: 'comp1'.mixins: [logMixin],
// ...
}
Copy the code
After some modification, you will find that product manager sister can also be so charming, is not you began to believe in love……
Run the project and open the console output as follows:
Component comp1 created.
Component comp2 created.
Copy the code
Case 2
Dot the requirements of the above components, now we have new requirements, need to add a generic method sayHello to certain components into the methods, and call after the component rendering, but just need to add the dot above the part of the component function, although only part of the component, but also have a hundreds (exaggeration, do not imitate). Hear here, you silently pushed away the side of the product sister, refused: SORRY, I have not believed in love. At this point, there is a voice in the light whisper: you can still believe! .
Okay, well, I’m gonna convince you one more time. First add the file SRC /mixins/func.js:
export default {
mounted() {
this.sayHello();
},
methods: {
sayHello() {
console.log('Product girl, you are beautiful! '); ,}}};Copy the code
Then add it to the required component:
import logMixin from '@/mixins/log';
import funcMixin from '@/mixins/func';
export default {
name: 'comp1'.mixins: [logMixin, funcMixin],
// ...
}
Copy the code
Run the project and open the console output as follows:
Component comp1 created. Component comp2 created. Component comp1 mounted. Product girl, you are beautiful! Component comp2 mounted.Copy the code
Case 3
All right, you can finally run into the sunset with the product girl. Suddenly one day, the component rendering after the dot, became the company’s specification, that is, all the components you write need dot, the product sister very helplessly looked at you and said: this is not the result I want, is that you do too good, was put on the company’s agenda, write the code specification….. But the reality is such, you always want to escape, escape cannot drop…… however
You can still run, Says Vue. Mixin.
Globally register a mixin that affects all Vue instances created after registration. Plug-in authors can use interfuse to inject custom behavior into components. Not recommended for use in application code.
Isn’t this the love you’ve been looking for? So you remove the logMixin you introduced earlier and silently write a declaration of love in the entry file (SRC /main.js) :
/ /...
Vue.mixin({
created() {
console.log(`Component The ${this.$options.name}Created from global rBI);
},
mounted() {
console.log(`Component The ${this.$options.name}Mounted from specifies the global id); }});// new Vue....
Copy the code
Run the project and open the console output as follows:
Component undefined created fromComponent App CreatedfromComponent Index createdfromComponent router-link createdfromComponent comp1 createdfromComponent comp1 created. Component comp2 createdfromComponent comp2 created. Component comp3 createdfromComponent Router-link MountedfromComponent comp1 MountedfromComponent comp1 Mounted Component comp2 mountedfromComponent comp2 mounted. Component comp3 mountedfromComponent Index MountedfromComponent App MountedfromGlobal hit Componentundefined mounted fromGlobal dotCopy the code
You’ll notice that all Vue components are injected with dots.
The principle of analytic
Mixins are pretty simple to use, but it’s worth digging into the principles behind them:
- why
mixins
After that, hook functions are executed sequentially, instead of substituting? - why
mixins
After theirdata
Property over mixin property?
To answer these questions, we have to start with the vue source code.
Vue initializes mixins using different strategies for different attributes. The initialization code can be found in the file SRC /core/global-api.js as follows:
import { mergeOptions } from '.. /util/index'
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
Vue.options = mergeOptions(Vue.options, mixin)
}
}
Copy the code
You will find that is merged by mergeOptions function, it in the file SRC/core/util/options. The js, its source code is as follows:
/** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. */
export function mergeOptions (parent: Object, child: Object, vm? : Component) :Object {
// omit unnecessary code
for (key in child) {
if(! hasOwn(parent, key)) { mergeField(key) } }function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
Copy the code
This function is easy to understand, and basically what it does is merge the attributes of the child into the parent, with different attributes adopting different policies defined on the Strats object.
Let’s start by looking at the merge strategy for lifecycle functions as follows:
/** * Hooks and param attributes are merged as arrays. */
function mergeHook (parentVal: ? Array
, childVal: ? Function | ? Array
): ?Array<Function> {
return childVal
? parentVal
? parentVal.concat(childVal)
: Array.isArray(childVal)
? childVal
: [childVal]
: parentVal
}
Copy the code
You can see that the lifecycle functions of the Vue instance end up being assigned an array, and array merges are performed in mixins. This is why the lifecycle functions after component mixins are executed sequentially.
Let’s also look at data’s join strategy:
/** * Helper that recursively merges two data objects together. */
function mergeData (to: Object, from: ? Object) :Object {
let key, toVal, fromVal
for (key in from) {
toVal = to[key]
fromVal = from[key]
if(! hasOwn(to, key)) { set(to, key, fromVal) }else if (isObject(toVal) && isObject(fromVal)) {
mergeData(toVal, fromVal)
}
}
return to
}
Copy the code
This process is the merging of object attributes, but the priority of to is higher than that of FROM. This is why, when mixins are made for a component, the priority of its own data is higher than that of the mixed data attribute. In other words, if the mixins and itself contain the same attribute, Mixin property values are not added to the current component.
SRC /core/util/options.js is available in the source code, which is also easy to understand.
conclusion
The more simple things, the more double-edged sword, the actual use must pay attention to, especially global mixed, which will bring performance overhead. You can write more, more summary, to find the most appropriate use habits, it is recommended to read the source code of famous open source projects, you will learn more skills of predecessors.
The source code in this
Project directory
You-May-Not-Know-Vuejs