Vue 組件循環嵌套引用問題

項目開發中,經常會出現組件之間循環嵌套的問題,下面我們以 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')

測試下了果然報錯就沒了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容