use
-
The use of extends
-
Allows the extension of another component, either a simple object or a constructor, without the need for extend, primarily to facilitate the extension of single-file components, similar to mixins.
-
The main function is the same as the component, but it is used on a single page rather than globally
-
var CompA = { ... } // Inherit CompA without calling 'vue. extend' var CompB = { extends: CompA, } Copy the code
-
-
How Mixins are used
-
Receive an array of mixins that can contain instance objects just like normal instance objects, and the options will be incorporated into the final options.
-
Mixin hooks are called in the order they are passed in and are called before the component’s own hooks are called
-
var mixin = { created: function () { console.log(1)}}var vm = new Vue({ created: function () { console.log(2)},mixins: [mixin] }) / / = > 1 / / = > 2 Copy the code
-
Realize the principle of
- Source code analysis
export function mergeOptions (
parent: Object,
child: Object, vm? : Component) :Object {... Format some propertiesif(! child._base) {if (child.extends) { Child. extends can be a constructor and an object
parent = mergeOptions(parent, child.extends, vm)
}
if (child.mixins) { // Child-. mixins[I] is an object that merges the data in mixins in sequence
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
}
const options = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if(! hasOwn(parent, key)) { mergeField(key) } }// Merge data
function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
Copy the code
The main part of this merge function is that the mergeField function strats[key] is merged in a way that requires looking at option.js to see the specific method of the attribute, as shown below
// strats
const strats = config.optionMergeStrategies
Copy the code
-
el
Merge method of-
if(process.env.NODE_ENV ! = ='production') { strats.el = strats.propsData = function (parent, child, vm, key) { if(! vm) { warn(`option "${key}" can only be used during instance ` + 'creation with the `new` keyword.')}return defaultStrat(parent, child) } } Copy the code
- This is only done in the development environment, if not passed in
vm
On the prompt message and passdefaultStrat
Methods tochild
To replace the data onparent
The data in the
- This is only done in the development environment, if not passed in
-
-
data
Merge method of-
strats.data = function ( // Merge the data of the two objectsparentVal: any, childVal: any, vm? : Component): ?Function { if(! vm) {if (childVal && typeofchildVal ! = ='function') { process.env.NODE_ENV ! = ='production' && warn( 'The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm ) return parentVal } return mergeDataOrFn(parentVal, childVal) } return mergeDataOrFn(parentVal, childVal, vm) } Copy the code
- If it’s not passed in
vm
Object: If the child element is not a function, it is prompted in the development environmentThe data attribute should be a function....
, and return the parent element; Or merge the parent and child elements - If the incoming
vm
Object: Merges the parent and child elements
- If it’s not passed in
-
//mergeDataOrFn merge method export function mergeDataOrFn (parentVal: any, childVal: any, vm? : Component): ?Function { if(! vm) {if(! childVal) {return parentVal } if(! parentVal) {return childVal } return function mergedDataFn () { return mergeData( typeof childVal === 'function' ? childVal.call(this.this) : childVal, typeof parentVal === 'function' ? parentVal.call(this.this) : parentVal ) } } else { return function mergedInstanceDataFn () { // instance merge const instanceData = typeof childVal === 'function' ? childVal.call(vm, vm) : childVal const defaultData = typeof parentVal === 'function' ? parentVal.call(vm, vm) : parentVal if (instanceData) { return mergeData(instanceData, defaultData) } else { return defaultData } } } } Copy the code
- There is no
vm
Object: returns the parent element if any argument is empty; Or you can merge the parent element’s method to the completed object - With the incoming
vm
Object: returns the result of combining the parent and child elements
- There is no
-
// mergeData concrete object merge method function mergeData (to: Object.from:?Object) :Object { if (!from) return to let key, toVal, fromVal const keys = hasSymbol ? Reflect.ownKeys(from) : Object.keys(from) for (let i = 0; i < keys.length; i++) { key = keys[i] // in case the object is already observed... if (key === '__ob__') continue toVal = to[key] fromVal = from[key] if(! hasOwn(to, key)) { set(to, key, fromVal)// Set from, which does not exist in to, to the object } else if( toVal ! == fromVal &&// If two pieces of data are different and both are objects, then bind all elements recursively isPlainObject(toVal) && isPlainObject(fromVal) ) { mergeData(toVal, fromVal) } } return to } Copy the code
- Access to the
from
And loop over the property. ifto
Object that does not have the property, will be directly bound to theto
In the object. ifto
The default is not to bind this property to an existing object. If the value of the property of two objects is different and both objects are objects, the property of this object will be looped together.
- Access to the
-
-
Life cycle merging approach
-
export const LIFECYCLE_HOOKS = [ 'beforeCreate'.'created'.'beforeMount'.'mounted'.'beforeUpdate'.'updated'.'beforeDestroy'.'destroyed'.'activated'.'deactivated'.'errorCaptured'.'serverPrefetch' ] LIFECYCLE_HOOKS.forEach(hook= > { strats[hook] = mergeHook }) Copy the code
-
// mergeHook merges the hook function method function mergeHook ( parentVal: ?Array<Function>, childVal: ?Function|?Array<Function> ): ?Array<Function> { const res = childVal ? parentVal ? parentVal.concat(childVal) : Array.isArray(childVal) ? childVal : [childVal] : parentVal return res ? dedupeHooks(res) : res } Copy the code
- The main is to put the parent function into the array to return, to achieve the merge
-
-
component
|directive
|filter
Merge method of-
export const ASSET_TYPES = [ 'component'.'directive'.'filter' ] ASSET_TYPES.forEach(function (type) { strats[type + 's'] = mergeAssets }) Copy the code
-
function mergeAssets ( parentVal: ?Object, childVal: ?Object, vm? : Component, key: string) :Object { const res = Object.create(parentVal || null) if(childVal) { process.env.NODE_ENV ! = ='production' && assertObjectType(key, childVal, vm) return extend(res, childVal) // Pass the data from the child object to the parent object } else { return res } } Copy the code
-
export function extend (to: Object, _from: ?Object) :Object { for (const key in _from) { to[key] = _from[key] } return to } Copy the code
- if
childVal
If there is data in theparentVal
All the bindings inchildVal
, but for data of the same property,childVal
Will coverparentVal
The data in the
- if
-
-
watch
Merge method of-
strats.watch = function ( parentVal: ?Object, childVal: ?Object, vm? : Component, key: string): ?Object {... Format validation, etc.const ret = {} extend(ret, parentVal) for (const key in childVal) { let parent = ret[key] const child = childVal[key] if (parent && !Array.isArray(parent)) { parent = [parent] } ret[key] = parent ? parent.concat(child) : Array.isArray(child) ? child : [child] } return ret } Copy the code
childVal
Is looping toparentVal
, if theparentVal
If the same attribute exists, parentValand
The corresponding property value in childVal ‘is placed in the array and then used as the property value
-
-
props
|methods
|inject
|computed
Merge method of-
strats.props = strats.methods = strats.inject = strats.computed = function ( parentVal: ?Object, childVal: ?Object, vm? : Component, key: string): ?Object { if(childVal && process.env.NODE_ENV ! = ='production') { assertObjectType(key, childVal, vm) } if(! parentVal)return childVal const ret = Object.create(null) extend(ret, parentVal) if (childVal) extend(ret, childVal) return ret } Copy the code
- The merge method is that the latter directly overwrites the former data of the same attribute, and the different data can be directly bound to it
-
-
provide
Merge method of-
strats.provide = mergeDataOrFn Copy the code
- with
data
In the same way
- with
-
// config.optionMergeStrategies
export type Config = {
optionMergeStrategies: { [key: string]: Function };
};
export default ({
optionMergeStrategies: Object.create(null),
}: Config)
Copy the code
// defaultStrat directly covers
const defaultStrat = function (parentVal: any, childVal: any) :any {
return childVal === undefined
? parentVal
: childVal
}
Copy the code
conclusion
Data, provide: The attributes are directly bound to the target object if the target object does not have them. If the target object already exists, it is not bound, but if the property values of the property object are both objects, it is necessary to recursively merge the binding operation on the property value object.
Life cycle: At merge time, replace the property value of the hook function of the target object with an array containing the corresponding function of the target object and the corresponding function of the bound object
Component | directive | filter, props | the methods | inject | computed: at the time of merger, are attributes of the object will be binding on circulation, direct binding target object does not exist, is directly covered
Watch: During the merge, if the target object and the merged object have the same properties, the same properties will be merged, and the different properties will not be bound. The merge is done primarily by replacing the property value with an array containing the object methods of the target object and the corresponding functions of the object to be bound