• Vue 动态组件渲染问题分析


    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:海豚湾-丰

       

  • 相关阅读:
    rails3 routes
    rails delete destroy difference
    ruby doc
    今天提交了一个patch开心,呵呵
    ruby collect map seems the function is the same?
    jquery closest
    rails 笔记
    网店系统
    rails脚本架命令及心得
    rails3 expericence
  • 原文地址:https://www.cnblogs.com/teamblog/p/10438293.html
Copyright © 2020-2023  润新知