<template>
  <div v-if="!item.hidden" class="menu-wrapper">
    <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
      <app-link v-if="item.redirect != 'noRedirect' && onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
        <el-menu-item
          :index="resolvePath(onlyOneChild.path)"
          :class="{ 'submenu-title-noDropdown': !isNest }"
        >
          {{ onlyOneChild.meta.title }}
        </el-menu-item>
      </app-link>
    </template>
<pre><code>&lt;el-submenu
  v-else
  ref=&quot;subMenu&quot;
  :index=&quot;resolvePath(item.path)&quot;
  popper-append-to-body
&gt;
  &lt;template slot=&quot;title&quot;&gt;
    &lt;item
      v-if=&quot;item.meta&quot;
      :icon=&quot;item.meta &amp;&amp; item.meta.icon&quot;
      :title=&quot;item.meta.title&quot;
    /&gt;
  &lt;/template&gt;
  &lt;sidebar-item
    v-for=&quot;child in item.children&quot;
    :key=&quot;child.path&quot;
    :is-nest=&quot;true&quot;
    :item=&quot;child&quot;
    :base-path=&quot;resolvePath(child.path)&quot;
    class=&quot;nest-menu&quot;
  /&gt;
&lt;/el-submenu&gt;
</code></pre>
  </div>
</template>
<script>
import path from 'path'
import { Validator } from '@bigbighu/cms-utils'
import Item from './Item'
import AppLink from './Link'
import FixiOSBug from './FixiOSBug'

export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
  mixins: [FixiOSBug],
  props: {
    // route object
    item: {
      type: Object,
      required: true
    },
    isNest: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String,
      default: ''
    }
  },
  data() {
    // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
    // TODO: refactor with render function
    this.onlyOneChild = null
    return {}
  },
  methods: {
    hasOneShowingChild(children = [], parent) {
      const showingChildren = children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          this.onlyOneChild = item
          return true
        }
      })

      // When there is only one child router, the child router is displayed by default
      // if (showingChildren.length === 1) {
      //   return true
      // }

      // Show parent if there are no child router to display
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
        return true
      }
      console.log(children, 'children')
      return false
    },
    resolvePath(routePath) {
      console.log(this.onlyOneChild, 'onlyOneChild')
      console.log(path.resolve(this.basePath, routePath), 'routePath')
      if (Validator.isExternal(routePath)) {
        return routePath
      }
      if (Validator.isExternal(this.basePath)) {
        return this.basePath
      }
      return path.resolve(this.basePath, routePath)
    }
  }
}
</script>
<style lang="less" scope>
#app .hideSidebar .el-submenu > .el-submenu__title .iconfont {
  margin-left: 18px;
}
</style>
<h2>代码详解</h2>
<p>该代码片段是一个 Vue.js 侧边栏菜单组件 <code>SidebarItem</code> 的实现。该组件接收一个路由对象作为 <code>item</code> 属性,并根据该对象的信息递归地渲染菜单项。</p>
<p>组件的主要逻辑如下:</p>
<ol>
<li>
<p><strong>判断是否显示菜单项</strong>: 首先,组件会根据 <code>item.hidden</code> 属性判断是否需要隐藏该菜单项。如果 <code>item.hidden</code> 为 true,则不会渲染该菜单项。</p>
</li>
<li>
<p><strong>判断是否只有一个子菜单项需要显示</strong>: 接着,组件会判断该菜单项是否有子菜单项,以及是否有子菜单项需要显示。如果只有一个子菜单项需要显示,则会使用 <code>el-menu-item</code> 组件渲染该子菜单项。</p>
</li>
<li>
<p><strong>判断是否需要重定向</strong>: 如果该菜单项有 <code>redirect</code> 属性,并且 <code>redirect</code> 属性的值不为 <code>noRedirect</code>,则会使用 <code>app-link</code> 组件渲染一个链接,该链接会指向子菜单项的路径。</p>
</li>
<li>
<p><strong>递归渲染子菜单项</strong>: 如果该菜单项有多个子菜单项,则会使用 <code>el-submenu</code> 组件渲染一个子菜单。子菜单中的子菜单项会使用 <code>sidebar-item</code> 组件递归地渲染。</p>
</li>
<li>
<p><strong>处理 <code>basePath</code></strong>: 组件会使用 <code>resolvePath</code> 方法来处理 <code>basePath</code> 属性。<code>basePath</code> 属性用于指定当前菜单项的根路径,该路径会被用于计算子菜单项的路径。</p>
</li>
</ol>
<h2>代码中的关键点</h2>
<ul>
<li><code>hasOneShowingChild</code> 方法用于判断是否只有一个子菜单项需要显示。</li>
<li><code>resolvePath</code> 方法用于处理 <code>basePath</code> 属性。</li>
<li><code>el-submenu</code> 和 <code>el-menu-item</code> 组件是 Element UI 框架中的菜单组件。</li>
<li><code>app-link</code> 组件是一个自定义组件,用于渲染链接。</li>
<li><code>Validator.isExternal</code> 方法用于判断一个路径是否是外部路径。</li>
</ul>
<h2>总结</h2>
<p>这段代码是一个典型的 Vue.js 侧边栏菜单组件实现,它使用了递归、条件判断和路径处理等技术,实现了根据路由信息动态渲染菜单的功能。开发者可以根据自己的需求修改该组件,以实现更加复杂的菜单功能。</p>
Vue.js 侧边栏菜单组件:SidebarItem 实现与逻辑详解

原文地址: https://www.cveoy.top/t/topic/nDhA 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录