vue里面,我们是可以自己传一些数据进去的。比如说
var vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
像这种的话,我们在new Vue的时候传了一个对象。就是
{
el: '#app',
data: {
message: 'Hello Vue!'
}
}
那么其实我们新建的这个Vue实例,会在代码运行后增加很多新的东西进去。我们把我们传入的这个对象叫options,这篇博客主要讲的就是关于vm.$options这个属性,这个属性在vue整个框架中都是不断出现的。所以弄清楚vm.$options对于源码阅读也十分有裨益。
先上一个随心所欲的图
下面一步步讲~
首先我们要找vm.$options最开始是在哪里出现的。在initMixin这个函数里面最早出现vm.$options的定义。
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
我们结合图看,mergeOptions
主要分成两块,就是resolveConstructorOptions(vm.constructor)
和options
,mergeOptions
这个函数的功能就是要把这两个合在一起。
options是我们自己写代码的时候传进去的,
因此需要看看的就是resolveConstructorOptions
这一块。resolveConstructorOptions
这个函数主要就是返回构造函数里面的options。
resolveConstructorOptions
export function resolveConstructorOptions (Ctor: Class<Component>) {
let options = Ctor.options
if (Ctor.super) {
const superOptions = resolveConstructorOptions(Ctor.super)
const cachedSuperOptions = Ctor.superOptions
if (superOptions !== cachedSuperOptions) {
// super option changed,
// need to resolve new options.
Ctor.superOptions = superOptions
// check if there are any late-modified/attached options (#4976)
const modifiedOptions = resolveModifiedOptions(Ctor)
// update base extend options
if (modifiedOptions) {
extend(Ctor.extendOptions, modifiedOptions)
}
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
if (options.name) {
options.components[options.name] = Ctor
}
}
}
return options
}
这里对应一下前面的图,就是把本身的options和父类的options合起来。
mergeOptions
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
if (process.env.NODE_ENV !== 'production') {
checkComponents(child)
}
if (typeof child === 'function') {
child = child.options
}
normalizeProps(child, vm)
normalizeInject(child, vm)
normalizeDirectives(child)
const extendsFrom = child.extends
if (extendsFrom) {
parent = mergeOptions(parent, extendsFrom, 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) { // 遍历Vue.options对象的属性
mergeField(key)
}
for (key in child) { // 遍历options对象的属性
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) { // 每个key都会对应在strats中初始化好的函数
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
- vm.constructor里面主要有哪些options:components,directives,filters,还有一个_base用来指向构造函数自身。initGlobalAPI这个函数中有许多初始化构造函数的代码,给构造函数添加options就在其中。可以看看初始化的代码:
function initGlobalAPI (Vue) {
// config
var configDef = {};
configDef.get = function () { return config; };
if (process.env.NODE_ENV !== 'production') {
configDef.set = function () {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
);
};
}
Object.defineProperty(Vue, 'config', configDef);
// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
Vue.util = {
warn: warn,
extend: extend,
mergeOptions: mergeOptions,
defineReactive: defineReactive
};
Vue.set = set;
Vue.delete = del;
Vue.nextTick = nextTick;
Vue.options = Object.create(null); // 这里开始
ASSET_TYPES.forEach(function (type) { // 添加components,directives,filters
Vue.options[type + 's'] = Object.create(null);
});
// this is used to identify the "base" constructor to extend all plain-object
// components with in Weex's multi-instance scenarios.
Vue.options._base = Vue; // 指向Vue本身的 _base
extend(Vue.options.components, builtInComponents); // 把builtInComponents里面的属性添加到Vue.options.components里面
initUse(Vue);
initMixin$1(Vue);
initExtend(Vue);
initAssetRegisters(Vue);
}