美文网首页时光轴Vue
Vue 组件循环嵌套引用问题

Vue 组件循环嵌套引用问题

作者: 侯工 | 来源:发表于2021-03-31 11:13 被阅读0次

    项目开发中,经常会出现组件之间循环嵌套的问题,下面我们以 Element-Ui 中的 NavMenu导航菜单组件二次封装为例。暂不考虑 el-menu-item-group 的问题,将 NavMenu 拆分成如下的几个小组件。

    一、组件代码

    menu-item

    menu-item为原导航菜单组件的el-menu-item,大致代码如下:

    <template>
      <div class="meun-item">
        <sub-menu v-if="menu.subMenu && menu.subMenu.length" :menu="menu" />
        <router-link v-else :to="menu.path">
          <el-menu-item :index="menu.menuName" :disabled="!!menu.disabled">
            <template slot="title">
              <i v-if="menu.icon" :class="['iconfont', menu.icon]"></i>
              <span class="menu-text">{ { menu.label }}</span>
            </template>
          </el-menu-item>
        </router-link>
      </div>
    </template>
    <script>
      import SubMenu from './sub-menu.vue'
      export default {  
        props: {
          menu: Object
        },  
        components: {
          SubMenu
        }
      }
    </script>
    

    sub-menu

    sub-menu为原导航菜单组件的el-submenu,大致代码如下:

    <template>
      <el-submenu :index="menu.menuName">
        <template slot="title">
          <i v-if="menu.icon" :class="['iconfont', menu.icon]"></i>
          <span class="menu-text">{ { menu.label }}</span>
        </template>
        <menu-item
          v-for="(item, index) in menu.subMenu || []"
          :menu="item"
          :key="index"
        /> </el-submenu
    ></template>
    <script>
      import MenuItem from './menu-item.vue'
      export default { 
        name: 'SubMenu',
        props: {
          menu: Object
        },  
        components: {
          MenuItem
        }
      }
    </script>
    

    nav-menu

    nav-menu为原导航菜单组件的el-menu

    <template>
      <el-menu class="nav-menu">
        <template v-for="(menu, index) in menus">
          <sub-menu
            v-if="menu.subMenu && menu.subMenu.length"
            :menu="menu"
            :key="`sub-menu-${index}`"
          />
          <menu-item v-else :menu="menu" :key="`menu-item-${index}`" />
        </template> </el-menu
    ></template>
    <script>
      import MenuItem from './menu-item.vue'
      import SubMenu from './sub-menu.vue'
      export default {
        props: {
          menus: Array
        },
        components: {
          MenuItem,
          SubMenu
        }
      }
    </script>
    

    二、组件调用

    <template>
      <nav-menu :menus="menus"/>
    </template>
    <script>
      import NavMenu from '@/components/nav-menu/nav-menu'
      export default {  
        components: {    NavMenu  },  
        data () {
          return {
            menus: [
              { label: "菜单1", menuName: "1", path: "" },
              {
                label: "菜单2",
                menuName: "2",
                subMenu: [
                  { label: "菜单2-1", menuName: "2-1", path: "" },
                  {
                    label: "菜单2-2",
                    menuName: "2-2",
                    subMenu: [{ label: "菜单2-2-1", menuName: "2-2-1", path: "" }],
                  },
                ],
              },
              { label: "菜单3", menuName: "3" },
            ],
          }
        }
      }
    </script>
    

    三、出现报错情况

    image

    然后就会出现一个组件未注册的报错情况,然后仔细查代码,看不是否有menu-item拼错了,发现没有,都是对的,每次刷新页面都会报这个错误,导致子集菜单不显示。最后用排除大法,将menu-item中的sub-menu注释掉后该报错没有了,目测问题应该是出现在这儿,但是sub-menu也没啥问题啊,百思不得其解,Google了半天才找到答案。

    四、总结

    归根结底还是组件之间的循环引用造成的问题,正如上面的链接所说的,有两个组件称为 A 和 B(A、B就相当于这里的 menu-itemsub-menu )。模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。官方给的解决方法就是异步加载组件。将上面的 import 加载的方式全部变成异步加载,代码如下:

    const MenuItem = () => import('./menu-item.vue')
    const SubMenu = () => import('./sub-menu.vue')
    

    测试下了果然报错就没了。

    相关文章

      网友评论

        本文标题:Vue 组件循环嵌套引用问题

        本文链接:https://www.haomeiwen.com/subject/rcyohltx.html