Yan Dong, Front End Engineer, Front End Technology Department, Wemicro. Aspiring to become a full stack development engineer or even architect, I have a long way to go. Exercise in your life to release stress and think about problems.
The article is long, so it is recommended to spend a whole block reading the analysis. In addition, because the length is too long, this paper is divided into three articles output, easy for everyone to understand and read.
MergeOptions function
In an article on the analysis, we have finished analysis resolveConstructorOptions mergeOptions function of the first parameter, we look back at the function mergeOptions again.
Merges the options passed in the constructor with the options passed in the instantiation and generates a new option
The mergeOptions function merges the options on the instance constructor, the options passed in during the instantiation, and the current instance into a single option.
export function mergeOptions (
parent: Object.// Options on the instance constructor
child: Object.// Options passed in when instantiatingvm? : Component// The current instance
) :Object {
if(process.env.NODE_ENV ! = ='production') {
checkComponents(child)
}
if (typeof child === 'function') {
child = child.options
}
normalizeProps(child, vm)
normalizeInject(child, vm)
normalizeDirectives(child)
// Apply extends and mixins on the child options,
// but only if it is a raw options object that isn't
// the result of another mergeOptions call.
// Only merged options has the _base property.
if(! child._base) {if (child.extends) {
parent = mergeOptions(parent, child.extends, vm)
}
if (child.mixins) {
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) } }function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
Copy the code
- 1.
checkComponents(child)
Verify that the component name is valid - 2. If child (options) is of type function, we take its options property as child
- 3. Transform the props, inject, and directives into object form (
normalizeProps(child, vm)
.normalizeInject(child, vm)
.normalizeDirectives(child)
)
Article 1 and article 2 we will not do a detailed analysis, interested can consult. Component names, we should not be too special when using them
normalizeProps
Let’s see how Vue converts props. First, we need to understand the use of props. Generally, we have two types of props, one is an array form, and the other is an object form.
// It is an array
Vue.component('test-component', {
props: ['testData'].template: '<span>{{ testData }}</span>'
})
// Object form
Vue.component('test-component', {
props: {
testData: {
type: String.default: ' '}},template: '<span>{{ testData }}</span>'
})
Copy the code
Look again at the definition of the normalizeProps function
function normalizeProps (options: Object, vm: ? Component) {
const props = options.props
if(! props)return
const res = {}
let i, val, name
if (Array.isArray(props)) {
i = props.length
while (i--) {
val = props[i]
if (typeof val === 'string') {
name = camelize(val)
res[name] = { type: null}}else if(process.env.NODE_ENV ! = ='production') {
warn('props must be strings when using array syntax.')}}}else if (isPlainObject(props)) {
for (const key in props) {
val = props[key]
name = camelize(key)
res[name] = isPlainObject(val)
? val
: { type: val }
}
} else if(process.env.NODE_ENV ! = ='production') {
warn(
`Invalid value for option "props": expected an Array or an Object, ` +
`but got ${toRawType(props)}. `,
vm
)
}
options.props = res
}
Copy the code
This code declares the res variable, which is used to store the processed object, and assigns it to options.props.
- If props is an array, traverse an array of strings, assigning each key to {type: null}
That is, arrays are converted to:
{
testData: { type: null}}Copy the code
- If the props is an object, then the props is humped, and the value corresponding to the key is a pure object. If the value corresponding to the key is a pure object, the props is humped, and the res is returned. Instead of assigning {type: value} to res, the props of the object form should be converted to:
{
testData: {
type: String.default: ' '}}Copy the code
normalizeInject
/** * Normalize all injections into Object-based format */
function normalizeInject (options: Object, vm: ? Component) {
const inject = options.inject
if(! inject)return
const normalized = options.inject = {}
if (Array.isArray(inject)) {
for (let i = 0; i < inject.length; i++) {
normalized[inject[i]] = { from: inject[i] }
}
} else if (isPlainObject(inject)) {
for (const key in inject) {
const val = inject[key]
normalized[key] = isPlainObject(val)
? extend({ from: key }, val)
: { from: val }
}
} else if(process.env.NODE_ENV ! = ='production') {
warn(
`Invalid value for option "inject": expected an Array or an Object, ` +
`but got ${toRawType(inject)}. `,
vm
)
}
}
Copy the code
Also score groups and objects:
// Parent component provides 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// Inject 'foo' as an array of subcomponents
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
// Inject 'foo' as a child object
const Child = {
inject: {
foo: {
from: 'bar'.default: 'foo'}}}Copy the code
NormalizeInject will eventually become:
// array
{
foo: { from: 'foo'}}// object
{
foo: {
from: 'bar'.default: 'foo'}}Copy the code
normalizeDirectives
/** * Normalize raw function directives into object format. */
function normalizeDirectives (options: Object) {
const dirs = options.directives
if (dirs) {
for (const key in dirs) {
const def = dirs[key]
if (typeof def === 'function') {
dirs[key] = { bind: def, update: def }
}
}
}
}
Copy the code
Directives function and object are written:
// Object registration
Vue.directive('my-directive', {
bind: function () {},
inserted: function () {},
update: function () {},
componentUpdated: function () {},
unbind: function () {}})// Function registration (instruction function)
Vue.directive('my-directive'.function () {
// This is called by 'bind' and 'update'
})
Copy the code
The source code will treat functional instructions as bind and update calls, which means that functional instructions will be treated as:
{
'my-directive': {
bind: function () {},
update: function () {}}}Copy the code
Let’s look at the code below mergeOptions:
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm)
}
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
Copy the code
When a mixin or extends property is passed to an options (Child), Call mergeOptions again to merge mixins and extends into the instance constructor options (parent Options).
Lift chestnuts 🌰 :
const childComponent = Vue.component('child', {...mixins: [myMixin],
extends: myComponent
...
})
const myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin')}}}const myComponent = {
mounted: function () {
this.goodbye()
},
methods: {
goodbye: function () {
console.log('goodbye from mixin')}}}Copy the code
Mounted, created hook handlers, and methods are merged with parent options.
That’s the end of this piece. The mergeOptions function tells the following:
- Props is normalized to object form
{type: null} or {type: val}
- Inject is normalized as an object
{from: val}
- Standardization of directives
The bind, the update function
- The extends, mixins property of the passed option is merged
summary
In the next article, we’ll dive into the core code of the mergeOptions function: merge strategy.
Finally finished the analysis of merge options (three articles), every day out of sleep time to chew this, it is not easy to promote their growth, I hope to bring some inspiration to the cute, if there is any place feel not clear welcome to ask questions in the comments section below, discussion ~
See the little lovely people here, you can easily click a praise to encourage me to continue to create, creation is not easy, learn together, as soon as possible to achieve wealth freedom ~
The resources
- Vue2.0 source
Recommended reading
- Vue2.0 source code interpretation series (2) – open the merge option of Vue mystery gift box
- Vue2.0 source code interpretation series – from Vue mysterious gift box