fire 讀在最前面: 1、本文適用於有一定基礎的vue開發者,需要瞭解基本的vue渲染流程 2、本文知識點涉及vue構造器以及選項策略合併、<component> 渲染邏輯 問題描述: Child繼承自App,主程式通過true 和false來控制顯示 Child 還是 App,在動態<compo ...
fire
讀在最前面:
1、本文適用於有一定基礎的vue開發者,需要瞭解基本的vue渲染流程
2、本文知識點涉及vue構造器以及選項策略合併、<component> 渲染邏輯
問題描述:
Child繼承自App,主程式通過true 和false來控制顯示 Child 還是 App,在動態<component /> 中渲染出來的始終是App,代碼如下
Vue.config.productionTip = false; Vue.config.devtools = false; // ----------------options--------------------- const optionsA = { render: (h) => h('span', '我是options - 父'), }; const optionsB = { render: (h) => h('span', '我是options - 子'), }; const App = Vue.extend({ template: `<div> 當前組件: {{name}} <br/> <component :is="node" /> </div>`, data() { return { name: 'App', node: optionsA, } } }); const Child = App.extend({ name: 'Child', data() { return { name: 'Child', node: optionsB, } } }); const vm = new Vue({ el: '#app', data() { return { isSuper: true, }; }, components: { App, Child }, render(h) { const that = this; return h('div', {}, [ h('button', { on: { click: () => { this.isSuper = true; } }, }, '父類'), h('button', { on: { click: () => { this.isSuper = false; } }, }, '子類'), h(this.isSuper ? 'App' : 'Child') ]); }, });
如下圖(點擊父/子類切換,始終顯示的是 父文本):
關鍵執行順序分析:
1、App通過繼承Vue生成構造,Child通過繼承App生成構造
2、預設isSuper:true,渲染出App(<component :is="node" /> 編譯為render: _C(node),這個時候會在App的node中生成.Ctor)
3、切換isSuper:false,渲染出Child(這裡渲染的時候,生成的實例是App,這裡是不符合預期的,按理應該是Child)
3.1、生成Child實例的時候進行了data合併,這個時候data中node變數合併了App的node中的.Ctor($options合併策略),參照下圖
3.2、在_createElement的時候 node 當為component options / constructor 時,會驗證是否 node 是否為object,如果是會轉換為構造器 使用vue.extend
3.2、在Child中動態調用 new Ctor() (這個Ctor是App的),生成實例
最後附上大致流程圖:
備註:
1、Vue.extend會生成VueComponent構造器,內部包含一個Ctor,組件生成的時候就是調用這個new Ctor() 進行實例生成
2、選項中data的生成是延遲到實例生成的時候
3、createComponent在分支<component>渲染時,傳入Ctor為對象的時候,會轉換為構造器,這也是我們這個使用 const optionsA = {render: (h) => h('span', '我是options - 父'), }; 這種方式的問題根源所在
4、知道了問題所在,解決方式就比較多了,比如直接傳入構造器,比如繞開data值合併策略,使用method方式。
by:海豚灣-豐