Bootstrap

解锁Vue的潜力:封装递归组件的经验之谈(网站导航层架嵌套)

最近在使用BootstrapVue写一个网站(我也不知道为啥要用这个😂),使用到了NavBar+DropDown等一些组件的组合,可以自动创建一个响应式的效果,还不错。But…,这个DropDown只支持到二级。有人2019年就在Github上提了issue- dropdown submenu并且作者也给了回复,会在未来的版本加入这个功能,然后这都2024年了…
现有方案

  1. bootstrap-submenu,这个库看着很nice,实际用起来却不是那回事,可能是BootStrap版本不对
  2. 在issue里也提到了stackoverflow上有一个解决方案,也不适合自己的情况
  3. …其他jQuery方案
  4. 纯css方案可以做到3级菜单,但是复用性不太好,也达不到无限层级的目的(虽然大部分网站导航菜单都不会超过3级)
    开始手撕
    本次组件的封装是在Claude帮助下,经过我调教出来的😊,不过加深了我对递归组件的理解:渲染是从上往下递归,事件是从下往上递归(冒泡),完整代码直接放在了GitHub上完整代码
    代码片段解析
<template>
  <nav class="nav-menu" :class="{ horizontal: isHorizontal }" @mouseleave="closeAllMenus">
    <ul>
      <li v-for="item in items" :key="item.id" class="menu-item-wrapper" @mouseleave="closeSubMenu(item)">
        <div
          @mouseenter="openSubMenu(item)"
          @click="toggleSubMenu(item)"
          class="menu-item"
          :class="{ 'has-children': item.children, open: item.isOpen }"
          >
          <a @click="menuClick(item, true)" class="label">{{ item.label }}</a>

          <span v-if="item.children" class="arrow">▼</span>

        </div>

        <recursive-menu
          v-if="item.children"
          :items="item.children"
          class="sub-menu"
          :class="{ open: item.isOpen }"
          :is-horizontal="isHorizontal"
          @close-parent="closeParentMenus"
          @menu-click="menuClick"
          />
      </li>

    </ul>

  </nav>

</template>

点睛之笔我觉得还是属于closeParentMenusmenuClick,因为事件可能发生在三级菜单或者更深的层级,所以要把事件逐级传递到最外层。父子组件爱你在一个单文件组件里,可能不太好理解。可以想象成父子组件在不同的文件,最里层的子组件发送事件到上一层级,上一层级接收到事件后,再继续往上一层级发送事件,直到最顶级。最后实现了完美的效果。
感谢AI,感谢Claude,提高生产力😜

;