使用Vue实现一个当鼠标悬浮时出现,鼠标离开时消失的双层菜单

前言

分享一个基于Vue实现一个当鼠标悬浮时出现,鼠标离开时消失的双层菜单。同时也是为了以后需要类似的需求时,可以提供一个实现思路,以及可以快速ctrl+c和ctrl+v操作,提高工作效率~

一、示例代码

(1)/src/views/Example/DiyNavMenu/index.vue

<template>
  <div class="index">
    <ul>
      <li
        v-for="(item, index) in tabList"
        :key="index"
        :class="{ 'active-tab': index == activeTabIndex }"
        @mouseover="
          item.name == '项目管理'
            ? (item.isVisibleMenuBox = true)
            : (item.isVisibleMenuBox = false)
        "
        @mouseleave="
          item.isVisibleMenuBox = false;
          isVisibleSubMenuBox = false;
          isMenuHover = -1;
        "
      >
        <span class="tab-label">{
  { item.name }}</span>

        <div class="menu" v-show="item.isVisibleMenuBox">
          <div class="menu-box">
            <div class="menu-box-cascader">
              <div
                class="menu-item"
                v-for="(menuItem, menuIndex) in menuList"
                :key="menuIndex"
                :class="{ 'menu-hover': menuIndex == isMenuHover }"
                @mouseover="handleMenuMouseOver(menuItem, menuIndex)"
              >
                <span>{
  { menuItem.label }}</span>
                <i class="el-icon-arrow-right" />
              </div>
            </div>

            <div class="menu-box-cascader" v-show="isVisibleSubMenuBox">
              <div
                class="menu-item"
                v-for="(subMenuItem, subMenuIndex) in subMenuList"
                :key="subMenuIndex"
                @click="handleSubMenuClick(subMenuItem, subMenuIndex)"
              >
                <span>{
  { subMenuItem.label }}</span>
              </div>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data: () => ({
    // 默认激活的页签索引
    activeTabIndex: 1,
    // 页签列表
    tabList: [
      {
        name: '系统中心',
        isVisibleMenuBox: false,
      },
      {
        name: '项目管理',
        isVisibleMenuBox: false,
      },
      {
        name: '用户管理',
        isVisibleMenuBox: false,
      },
    ],
    // 菜单列表
    menuList: [
      {
        label: '卡拉OK项目工程',
        children: [
          {
            label: '卡拉一期',
          },
          {
            label: '卡拉二期',
          },
          {
            label: '卡拉三期',
          },
          {
            label: '卡拉四期',
          },
          {
            label: '卡拉五期',
          },
        ],
      },
      {
        label: '芭比Q项目工程',
        children: [
          {
            label: '芭比一期',
          },
          {
            label: '芭比二期',
          },
        ],
      },
      {
        label: '最流批的项目工程',
        children: [
          {
            label: '最流批一期',
          },
        ],
      },
    ],
    // 菜单索引
    isMenuHover: -1,
    // 子菜单是否可见
    isVisibleSubMenuBox: false,
    // 子菜单列表
    subMenuList: [],
  }),
  methods: {
    /**
     * 菜单鼠标悬浮事件
     */
    handleMenuMouseOver(menuItem, menuIndex) {
      this.isMenuHover = menuIndex
      if (menuItem.children) {
        this.isVisibleSubMenuBox = true
        this.subMenuList = menuItem.children
      }
    },

    /**
     * 子菜单点击事件
     */
    handleSubMenuClick(subMenuItem, subMenuIndex) {
      console.log('handleSubMenuClick ->', subMenuItem, subMenuIndex)
    },
  },
};
</script>

<style lang="less" scoped>
.index {
  width: 100%;
  height: 35px;
  display: flex;
  justify-content: center;
  background-color: #fff;
  border-bottom: 1px solid #eee;

  ul {
    min-width: 300px;
    height: 100%;
    display: flex;
    justify-content: space-between;

    li {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      list-style: none;
      position: relative;

      .tab-label {
        padding: 0px 10px;
        font-size: 14px;
        line-height: 34px;
        border-bottom: 1px solid transparent;
      }

      .tab-label:hover {
        border-bottom: 1px solid #072fbe;
        cursor: pointer;
        color: #072fbe;
      }

      .menu {
        position: absolute;
        top: 35px;
        left: 0;
        z-index: 10;
        width: 150px;
        height: auto;
        background-color: #fff;

        .menu-box {
          position: relative;
          display: flex;
          width: 100%;
          height: auto;

          .menu-box-cascader {
            width: 100%;
            height: 200px;
            background-color: #fff;
            border-radius: 5px;
            box-shadow: 1px 2px 8px 0 rgba(0, 0, 0, 0.15);

            &:nth-of-type(2) {
              position: absolute;
              top: 0;
              left: 152px;
              width: 180px;
              // background-color: #faf;
            }

            .menu-item {
              position: relative;
              width: 100%;
              height: 28px;
              display: flex;
              align-items: center;
              justify-content: center;
              cursor: pointer;

              span {
                font-size: 13px;
              }

              .el-icon-arrow-right {
                font-size: 12px;
                position: absolute;
                right: 2px;
              }

              &:hover {
                background-color: #072fbe1a;

                span, .el-icon-arrow-right {
                  color: #072fbe;
                }
              }
            }

            .menu-hover {
              background-color: #072fbe1a;

              span, .el-icon-arrow-right {
                color: #072fbe;
              }
            }
          }
        }
      }
    }

    .active-tab {
      // background-color: aqua;

      .tab-label {
        border-bottom: 1px solid #072fbe;
        color: #072fbe;
      }
    }
  }
}
</style>

二、运行效果

// Todo

最近更新

  1. TCP协议是安全的吗?

    2023-12-09 22:06:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-09 22:06:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-09 22:06:04       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-09 22:06:04       20 阅读

热门阅读

  1. 嵌入式安全学习路标

    2023-12-09 22:06:04       36 阅读
  2. 使用React 18和WebSocket构建实时通信功能

    2023-12-09 22:06:04       38 阅读
  3. 微前端 ---- wujie-vue3 原理

    2023-12-09 22:06:04       36 阅读
  4. vue2 el-input里实现打字机 效果

    2023-12-09 22:06:04       33 阅读
  5. C++ Primer Plus第十三章笔记

    2023-12-09 22:06:04       20 阅读
  6. 【GDB】

    【GDB】

    2023-12-09 22:06:04      24 阅读
  7. uni-app详解、开发步骤、案例代码

    2023-12-09 22:06:04       28 阅读
  8. Linux登录/重启时自动执行

    2023-12-09 22:06:04       44 阅读
  9. nginx root alias 区别

    2023-12-09 22:06:04       32 阅读