Vue.use
作用:插件安装
源代码:
Vue.use = function (plugin: Function | Object) {
const installedPlugins =
this._installedPlugins || (this._installedPlugins = []); // 所有的插件都保存在Vue._installedPlugins队列里
if (installedPlugins.indexOf(plugin) > -1) { // 避免重复安装
return this;
}
// 从第2个参数开始作为传入插件的参数
const args = toArray(arguments, 1);
args.unshift(this); // 将Vue构造函数作为第一个参数传入
// 如果插件实现了install函数,则调用
if (typeof plugin.install === "function") {
plugin.install.apply(plugin, args);
}
// 如果插件本事是一个函数,则调用
else if (typeof plugin === "function") {
plugin.apply(null, args);
}
installedPlugins.push(plugin);
return this;
};
解释: 详细解释见代码注释,从源码可以看出Vue维护了一个队列用于保存所有安装过的插件,插件的安装实际上是执行了插件的install方法(前提是插件实现了该方法)或者直接执行插件函数,其将接收一系列参数,其中第一个参数为Vue构造函数
Vue.mixin
作用:合并传入options和Vue.options
源代码:
function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
if (typeof child === 'function') {
child = child.options
}
normalizeProps(child, vm) // 标准化被合并props最终将输出{key: {type: String, default: ''}}类型
normalizeInject(child, vm) // 标准化inject
normalizeDirectives(child) // 标准化directives
const extendsFrom = child.extends
if (extendsFrom) { // 单独对child.extends进行合并
parent = mergeOptions(parent, extendsFrom, vm)
}
if (child.mixins) { // 如果child定义了mixins,则首先将其合并到parent,目的是降低其优先级
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)
}
}
// 针对不同类型的option调用不同的合并策略方法进行合并
function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin);
return this;
};
解释:Vue.mixin的作用就是将传入option和Vue.options做一次合并,对Vue.options进行拓展,具体的合并过程见代码注释
至于注释中提到的针对不同类型的option调用不同的合并策略方法,下面介绍几种合并策略:
// 使用源对象的属性覆盖目标对象的属性
function extend (to: Object, _from: ?Object): Object {
for (const key in _from) {
to[key] = _from[key]
}
return to
}
// 资源合并:源对象作为目标对象的原型,不对目标对象做覆盖
// 使用该策略合并的option有:components、directives、filters
function mergeAssets (
parentVal: ?Object,
childVal: ?Object,
vm?: Component,
key: string
): Object {
const res = Object.create(parentVal || null)
if (childVal) {
return extend(res, childVal)
} else {
return res
}
}
// 默认合并:如果目标对象为undefined则直接使用源对象,否则使用目标对象
// 使用该策略合并的option有:_base
function defaultStrat (parentVal: any, childVal: any): any {
return childVal === undefined
? parentVal
: childVal
}
// 覆盖合并:目标对象属性将覆盖源对象的属性
// 使用该策略的option有:props、methods、inject、computed
function merge (
parentVal: ?Object,
childVal: ?Object,
vm?: Component,
key: string
): ?Object {
if (!parentVal) return childVal
const ret = Object.create(null)
extend(ret, parentVal)
if (childVal) extend(ret, childVal)
return ret
}
... 其他合并策略不多做介绍
扩展:Vue.options的用途
在创建Vue实例的过程中首先需要将用户传入options和Vue.options进行一次合并,即全局定义的Vue.options将在每个实例中都能进行访问
// 这里的mergeOPtions方法上面已经有过介绍
vm.$options = mergeOptions(
vm.constructor.options, // 源码中并不简单是这样,这里便于理解
options || {},
vm
)
Vue.extend
作用:创建vue组件构造器
源代码:
Vue.extend = function (extendOptions: Object): Function { // 参数为用户自定义组件options
extendOptions = extendOptions || {};
const Super = this; // this指向Vue
const SuperId = Super.cid; // Vue的唯一标识
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {}); // 缓存
// 优先读取缓存,如果有缓存,直接返回缓存
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId];
}
// name: 组件名称
const name = extendOptions.name || Super.options.name;
// Sub继承自Vue(super)
const Sub = function VueComponent(options) {
this._init(options); // this._init继承自Vue
};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.cid = cid++;
// 合并Vue.options和component,该方法同Vue.mixin中调用的合并方法,具体参看Vue.mixin小节
Sub.options = mergeOptions(Super.options, extendOptions);
Sub["super"] = Super;
// 这里主要对props、computed做了一层代理Sub.key --> Sub._props.key
if (Sub.options.props) {
initProps(Sub);
}
if (Sub.options.computed) {
initComputed(Sub);
}
// 拷贝Vue的静态方法给Sub
Sub.extend = Super.extend;
Sub.mixin = Super.mixin;
Sub.use = Super.use;
// Sub.component = Vue.component Sub.directive = Vue.directive Sub.filter = Vue.filter
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type];
});
// 保证自身循环查找
if (name) {
Sub.options.components[name] = Sub;
}
// 保持对Vue.options 和 用户传入options的引用
Sub.superOptions = Super.options;
Sub.extendOptions = extendOptions;
Sub.sealedOptions = extend({}, Sub.options);
cachedCtors[SuperId] = Sub; // 缓存
// 返回值是一个构造函数
return Sub;
};
解释: 具体见代码注释
Vue.component & Vue.directive & Vue.filter
说明:这三个静态方法放在一起,在Vue中全局component、directive、filter都称为assets,他们公用一个方法
源代码:
const ASSET_TYPES = [
'component',
'directive',
'filter'
]
ASSET_TYPES.forEach((type) => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + "s"][id]; // 如果没有传入options则直接返回Vue.options.components[id]
} else {
if (type === "component" && isPlainObject(definition)) {
definition.name = definition.name || id;
definition = this.options._base.extend(definition); // 对于component调用Vue.extend创建组件构造器
}
if (type === "directive" && typeof definition === "function") {
definition = { bind: definition, update: definition };
}
this.options[type + "s"][id] = definition; // 将新增的definition保存在全局
return definition;
}
};
});
其它
Vue.set === Vue.prototype.$set
Vue.delete === Vue.prototype.$delete
Vue.nextTick === Vue.prototype.$nextTick