Vue 动态组件渲染问题分析
2019-02-26 21:09 海豚湾 阅读(8304) 评论(1) 编辑 收藏 举报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:海豚湾-丰