欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue.mixin Vue.extend(Vue.component)的原理与区别

程序员文章站 2022-03-20 20:09:21
1.本文将讲述 方法 Vue.extend Vue.mixin 与 new Vue({mixins:[], extend:{}})的区别与原理 先回顾一下 Vue.mixin 官网如下描述: Vue.mixin( mixin )全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。插件作者可以 ......

1.本文将讲述 方法 vue.extend vue.mixin 与 new vue({mixins:[], extend:{}})的区别与原理

     先回顾一下 vue.mixin 官网如下描述:

     vue.mixin( mixin )全局注册一个混入,影响注册之后所有创建的每个 vue 实例。插件作者可以使用混入,向组件注入自定义的行为。

     既然可以影响到注册后的所有实例,那么该方法注入的方法和属性都存放在哪里呢(构造函数的options属性上),我们一起来看看该方法的定义

     vue.mixin = function (mixin) {
             //mergeoption,将vue构造函数的options属性与传入的mixin参数进行合并,
             //合并之后再复制给vue构造函数的options属性
            this.options = mergeoptions(this.options, mixin);
            return this
        };

    为什么vue.mixin方法将mixin合并至vue.options就能影响注册之后的所有实例呢,让我们看看vue实例化的过程(将构造函数的options属性与实例化参数合并后付给实例的$options属性

 

 1    function vue(options) {
 2         //调用_init方法
 3         this._init(options);
 4     }
 5 
 6 
 7 
 8     vue.prototype._init = function (options) {
 9             var vm = this;
10             // a uid
11             vm._uid = uid$3++;
12 
13             var starttag, endtag;
14     
21             // a flag to avoid this being observed 标记该对象是一个vue实例
22             vm._isvue = true;
23             // merge options
24             if (options && options._iscomponent) { //组件实例化过程,即vue.extend返回对象--稍后解释
25                 // optimize internal component instantiation
26                 // since dynamic options merging is pretty slow, and none of the
27                 // internal component options needs special treatment.
28                 initinternalcomponent(vm, options);
29             } else {//将构造函数的options属性与实例化参数合并后付给实例的$options属性 ,该属性会在函数initstate中进行初始化
30                 vm.$options = mergeoptions(  
31                     resolveconstructoroptions(vm.constructor),
32                     options || {},
33                     vm
34                 );
35             }
36             /* istanbul ignore else */
37             {
38                 initproxy(vm);
39             }
40             // expose real self
41             vm._self = vm;
42             initlifecycle(vm);
43             initevents(vm);
44             initrender(vm);
45             callhook(vm, 'beforecreate');
46             initinjections(vm); // resolve injections before data/props
47             initstate(vm);
48             initprovide(vm); // resolve provide after data/props
49             callhook(vm, 'created');
50 
51             /* istanbul ignore if */
52             if ("development" !== 'production' && config.performance && mark) {
53                 vm._name = formatcomponentname(vm, false);
54                 mark(endtag);
55                 measure(("vue " + (vm._name) + " init"), starttag, endtag);
56             }
57 
58             if (vm.$options.el) {
59                 vm.$mount(vm.$options.el);
60             }
61         };

 

     vue.extend-- 使用基础 vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象 

     该方法返回一个与vue具有相同功能的构造函数(其实为创建了一个组件)-属性options是 合并  基础 vue 构造器 与 extend的参数 的对象,

     

 vue.extend = function (extendoptions) {
            extendoptions = extendoptions || {};
            //将调用函数付给super 
            var super = this;  
            var superid = super.cid;
            //如果参数中参入与创建的构造函数则直接返回
            var cachedctors = extendoptions._ctor || (extendoptions._ctor = {});
            if (cachedctors[superid]) {
                return cachedctors[superid]
            }
            //获取组件的名称
            var name = extendoptions.name || super.options.name;
            if ("development" !== 'production' && name) {
                validatecomponentname(name);
            }
            //创建组件sub
            var sub = function vuecomponent(options) {
                this._init(options);
            };
       //为组件添加对应的属性与方法 sub.prototype = object.create(super.prototype); sub.prototype.constructor = sub; sub.cid = cid++;
//合并super的options与extend的入参并赋值给sub的options属性 sub.options = mergeoptions( super.options, extendoptions );
//在sub上保存super的信息 sub['super'] = super; // for props and computed properties, we define the proxy getters on // the vue instances at extension time, on the extended prototype. this // avoids object.defineproperty calls for each instance created. if (sub.options.props) { initprops$1(sub); } if (sub.options.computed) { initcomputed$1(sub); } // allow further extension/mixin/plugin usage sub.extend = super.extend; sub.mixin = super.mixin; sub.use = super.use; // create asset registers, so extended classes // can have their private assets too. asset_types.foreach(function (type) { sub[type] = super[type]; }); // enable recursive self-lookup
//如果有组件名称,将该组件挂载到sub.options.components上。以便可在组件内使用
          if (name) { sub.options.components[name] = sub; } // keep a reference to the super options at extension time. // later at instantiation we can check if super's options have // been updated.
//保存option信息。以便在render的时候生成最新的options选项
sub.superoptions = super.options; sub.extendoptions = extendoptions; sub.sealedoptions = extend({}, sub.options); // cache constructor cachedctors[superid] = sub; return sub //返回sub构造函数 };

      vue.component( id, [definition] ) 注册或获取全局组件。注册还会自动使用给定的id设置组件的名称,第二个参数可以是object也可以调用vue.extend 返回的构造函数,返回组件

 调用vue.component 将调用vue.extend生成一个组件(构造函数),该组件将赋值给vue.options.components[id],由于在实例化时,将合并构造函数的options至实例对象的$options上,所有通过通过全局构造函数vue创建的组件或者视图都可以运用该组件,

 var asset_types = [
        'component',
        'directive',
        'filter'
    ];
//定义  vue.component .   vue.directive  vue.filter

asset_types.foreach(function (type) {
            vue[type] = function (
                id,
                definition
            ) {
                if (!definition) {
                    return this.options[type + 's'][id]
                } else {
                    /* istanbul ignore if */
                    if ("development" !== 'production' && type === 'component') {  
                        //对组件的命名规范进行验证
                        validatecomponentname(id);
                    }
                    if (type === 'component' && isplainobject(definition)) {
                       //如果第二个参数是一个object 调用  vue.extend(definition)生成一个构造函数   this.options._base === vue
                        definition.name = definition.name || id;
                        definition = this.options._base.extend(definition);
                    }
                    if (type === 'directive' && typeof definition === 'function') {
                        definition = { bind: definition, update: definition };
                    }
                    //将vue.options.components[id]赋值为 组件构造函数
                    this.options[type + 's'][id] = definition;
                    return definition
                }
            };
        });
    }

 

由以上代码可见  vue.component返回的组件即为  vue.extend创建的构造函数 -再次命名为subvue,subvue具有与vue一样的方法和属性,所以可调用subvue.component,subvue.extend创建组件,调用subvue.component,subvue.extend创建的组件组件将存放于subvue.options上,所以在通过subvue创建的组件,只能用于subvue实例化传入字符串模板的中模板使用,或者subvue.component,subvue.extend创建的组件实例化传入的字符串模板中使用。

   

   new vue({mixins:[], extend:{}})

     实例化选项mixins , extend将在init函数中通过mergeoptions合并至实例属性$options,他们的区别是extend为options对象,mixins为options数组,同时 extend的方法将比mixins先执行,但他们都会在  vue.extend 与  vue.mixin之后  执行