zoukankan      html  css  js  c++  java
  • Vue.mixin Vue.extend(Vue.component)的原理与区别

    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之后  执行

       

  • 相关阅读:
    07-JSP
    06-ServletContext和ServletConfig
    05-请求转发和重定向Login
    04-session学习
    03-cookie学习
    02-servlet生命周期和doget()_dopost()方法
    01-request和respone学习
    05-jQuery案例
    04-jQuery的事件机制和动画效果
    03-jQuery操作元素
  • 原文地址:https://www.cnblogs.com/riona/p/10030143.html
Copyright © 2011-2022 走看看