• Vue recursive multi-level menu

Vue recursive multi-level menu

⭐️ more front-end technology and knowledge, search subscription number JS bacteria subscription

Consider the following menu data:

[{name: "About".path: "/about".children: [{name: "About US".path: "/about/us"
      },
      {
        name: "About Comp".path: "/about/company".children: [{name: "About Comp A".path: "/about/company/A".children: [{name: "About Comp A 1".path: "/about/company/A/1"}]}]}, {name: "Link".path: "/link"}];Copy the code

Effects to be achieved:

Start by creating two components, Menu and MenuItem

// Menuitem

<template>
  <li class="item">
    <slot />
  </li>
</template>
Copy the code

A MenuItem is a LI tag and slot that allows you to add various elements to it

<! -- Menu -->

<template>
  <ul class="wrapper">
    <!-- 遍历 router 菜单数据 -->
    <menuitem :key="index" v-for="(item, index) in router">
      <! -- For items without children submenu -->
      <span class="item-title" v-if=! "" item.children">{{item.name}}</span>

      <! -- For items with children submenu -->
      <template v-else>
        <span @click="handleToggleShow">{{item.name}}</span>
        <! -- Recursive operation -->
        <menu :router="item.children" v-if="toggleShow"></menu>
      </template>
    </menuitem>
  </ul>
</template>

<script>
  import MenuItem from "./MenuItem";

  export default {
    name: "Menu".props: ["router"].// The Menu component accepts a router as Menu data
    components: { MenuItem },
    data() {
      return {
        toggleShow: false / / toggle state
      };
    },
    methods: {
      handleToggleShow() {
        // Handles whether to expand the submenu handler in the toggle state
        this.toggleShow = !this.toggleShow; }}};</script>
Copy the code

The outer layer of the Menu component is a UL label, and the inner part is a MenuItem generated by vFor traversal

There are two cases that need to be judged. One is that the item does not have the children attribute, and the title of the item can be rendered directly by adding a SPAN element in the slot of the MenuItem. The other is the item that contains the children attribute. In this case, not only do you need to render the title, but you also need to recursively introduce Menu again, passing item. Children as a route to the router prop

Finally used in the project:

<template>
  <div class="home">
    <menu :router="router"></menu>
  </div>
</template>

<script>
  import Menu from '@/components/Menu.vue'

  export default {
    name: 'home'.components: {
      Menu
    },
    data () {
      return {
        router: / /... Omit menu data}}}</script>
Copy the code

Finally add some styles:

MenuItem:

<style lang="stylus" scoped>
  .item {
    margin: 10px 0;
    padding: 0 10px;
    border-radius: 4px;
    list-style: none;
    background: skyblue;
    color: #fff;
  }
</style>
Copy the code

Menu:

<style lang="stylus" scoped>.wrapper { cursor: pointer; .item-title { font-size: 16px; }}</style>
Copy the code

The code inside the UL tag in Menu can be extracted separately, the Menu is used as a wrapper, and the code in the recursive operations section can be extracted separately

Please pay attention to my subscription number, push technical articles about JS irregularly, only talk about technology not gossip 😊