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

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM