vue制作无限级菜单栏

先上效果:


菜单栏1.gif

再上代码:
MenuPage.vue

<template>
  <div class="about">
    <Menu :menu_data="menu" :level="0"></Menu>
  </div>
</template>

<script>
import Menu from "@/components/Menu";
export default {
  components: {
    Menu,
  },
  data() {
    return {
      menu: [
        {
          name: "首页数据",
          children: [
            {
              name: "今日数据",
              children: [
                {
                  name: "上午数据",
                },
                {
                  name: "下午数据",
                },
              ],
            },
            {
              name: "本周数据",
            },
          ],
        },
        {
          name: "用户管理",
          children: [
            {
              name: "高管用户",
              children: [
                {
                  name: "销售部高管",
                },
                {
                  name: "技术部高管",
                },
              ],
            },
            {
              name: "普通用户",
              children: [
                {
                  name: "男性用户",
                },
                {
                  name: "女性用户",
                },
              ],
            },
          ],
        },
      ],
    };
  },
};
</script>

Menu.vue

<template>
  <div class="menu">
    <div v-for="(item, index) in menu_data" :key="index">
      <div @click="toggle_fold(item.name)" :style="{marginLeft: level * 4 + 'em'}">
        <span>{{item.name}}</span>
        <span :class="toggle_item == item.name ? 'indicator expand' : 'indicator'" v-if="item.children">></span>
      </div>
      
      <Menu v-if="item.children && (item.name == toggle_item)" :menu_data="item.children" :level="level + 1"></Menu>
      
      <!-- 记住子菜单的折叠状态用v-show,因为v-show是暂时将组件隐藏起来,所以会保留toggle_item;v-if会在销毁和重新创建过程中初始化toggle_item为null -->
      <!-- <Menu v-show="(item.name == toggle_item)" v-if="item.children" :menu_data="item.children" :level="level + 1"></Menu> -->
    </div>
  </div>
</template>

<script>
export default {
  name: "Menu",
  props: ["menu_data", "level"],
  data() {
    return {
      toggle_item: null,
    }
  },
  methods: {
    toggle_fold(name) {
      this.toggle_item = this.toggle_item == name ? null : name
    }
  },
}
</script>

<style lang="scss" scoped>
  .indicator {
    // 设置块状显示时旋转效果才会生效
    display: inline-block;
    transform:rotate(90deg) scale(1,2);    
  }

  .indicator.expand {
    // 设置块状显示时旋转效果才会生效
    display: inline-block;  
    transform:rotate(270deg) scale(1,2);
  }


</style>

第二种效果(不影响其它菜单的折叠状态):


菜单栏2.gif

Menu.vue

<template>
  <div class="menu">
    <div v-for="(item, index) in menu_data" :key="index">
      <div @click="toggle_fold(item.name)" :style="{marginLeft: level * 4 + 'em'}">
        <span>{{item.name}}</span>
        <span :class="unfold_items.indexOf(item.name) !== -1 ? 'indicator expand' : 'indicator'" v-if="item.children">></span>
      </div>
      
      <Menu v-if="item.children && unfold_items.indexOf(item.name) !== -1" :menu_data="item.children" :level="level + 1"></Menu>
      
      <!-- 记住子菜单的折叠状态用v-show,因为v-show是暂时将组件隐藏起来,所以会保留toggle_item;v-if会在销毁和重新创建过程中初始化toggle_item为null -->
      <!-- <Menu v-show="(item.name == toggle_item)" v-if="item.children" :menu_data="item.children" :level="level + 1"></Menu> -->
    </div>
  </div>
</template>

<script>
export default {
  name: "Menu",
  props: ["menu_data", "level"],
  data() {
    return {
      unfold_items: [],
    }
  },
  methods: {
    toggle_fold(name) {
      if (!this.in_unfold_item(name)) 
        this.unfold_items.push(name)
      else
        this.unfold_items = this.unfold_items.filter(e => e != name)
    },
    in_unfold_item(name) {
      return this.unfold_items.indexOf(name) !== -1
    }
  },

}
</script>

<style lang="scss" scoped>
  .indicator {
    // 设置块状显示时旋转效果才会生效
    display: inline-block;
    transform:rotate(90deg) scale(1,2);    
  }

  .indicator.expand {
    // 设置块状显示时旋转效果才会生效
    display: inline-block;  
    transform:rotate(270deg) scale(1,2);
  }

</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容