Vue рекурсивное многоуровневое меню

Vue.js

Vue рекурсивное многоуровневое меню

⭐️ Чтобы узнать больше о передовых технологиях и знаниях, найдите номера подписки.JS 菌подписка

Рассмотрим следующие данные меню:

[
  {
    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"
  }
];

Эффект, которого необходимо достичь:

20190503142723.png

Сначала создайте два компонента Menu и MenuItem.

// Menuitem

<template>
  <li class="item">
    <slot />
  </li>
</template>

MenuItem — это тег li и слот, позволяющий добавлять к нему различные элементы.

<!-- Menu -->

<template>
  <ul class="wrapper">
    <!-- 遍历 router 菜单数据 -->
    <menuitem :key="index" v-for="(item, index) in router">
      <!-- 对于没有 children 子菜单的 item -->
      <span class="item-title" v-if="!item.children">{{item.name}}</span>

      <!-- 对于有 children 子菜单的 item -->
      <template v-else>
        <span @click="handleToggleShow">{{item.name}}</span>
        <!-- 递归操作 -->
        <menu :router="item.children" v-if="toggleShow"></menu>
      </template>
    </menuitem>
  </ul>
</template>

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

  export default {
    name: "Menu",
    props: ["router"], // Menu 组件接受一个 router 作为菜单数据
    components: { MenuItem },
    data() {
      return {
        toggleShow: false // toggle 状态
      };
    },
    methods: {
      handleToggleShow() {
        // 处理 toggle 状态的是否展开子菜单 handler
        this.toggleShow = !this.toggleShow;
      }
    }
  };
</script>

Внешний слой компонента Menu — это тег ul, а внутренний слой — это MenuItem, сгенерированный vFor traversal.

Здесь следует рассмотреть два случая: во-первых, элемент не имеет атрибута children, и элемент span добавляется непосредственно в слот MenuItem для отображения заголовка элемента, а во-вторых, элемент содержит атрибут children. В этом случае нужно не только отрендерить заголовок, но и снова ввести Menu для рекурсивной работы, и передать item.children как маршрут к проп маршрутизатору.

Наконец, используйте в проекте:

<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: // ... 省略菜单数据
      }
    }
  }
</script>

Наконец, добавьте несколько стилей:

MenuItem:

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

Menu:

<style lang="stylus" scoped>
  .wrapper {
    cursor: pointer;

    .item-title {
      font-size: 16px;
    }
  }
</style>

Код в теге ul в меню можно извлечь отдельно, меню используется в качестве оболочки, а код в части рекурсивной операции также можно извлечь отдельно.

JS 菌公众账号

Пожалуйста, обратите внимание на мой номер подписки, время от времени я буду выкладывать технические статьи о JS, только говорить о технологиях, а не сплетничать 😊