在不使用ElementUi等框架的情况下,制作一个二级菜单,网上搜寻很多资料,但部分要不只显示HTML结构,不显示CSS样式,要不就是复杂的让人无法理解。

效果图:

element dropdown 实现二级菜单 vue二级菜单_子菜单

针对菜单做了CSS样式修饰,给一级二级菜单都添加了鼠标悬浮事件,当悬浮到某个菜单时,背景颜色,字体颜色发生改变。当点击某个一级菜单时,二级菜单实现显示和隐藏的动态切换。

菜单的HTML结构:
<div class="nav">
          --------------------一级菜单------------------
        <ul>
          <li
            v-for="item in menus"
            :key="item.id"
            @click="changeCheck(item.id)"
            :class="{ check: currentTag == item.path }"
            class="mainMenu"
          >
            <router-link
              :to="{name:item.path,params:userName}"
              class="mainA"
              @click.native="TabName(item.title)"
              >{{ item.title }}</router-link
            >
          ------------------二级菜单----------------------
            <ul v-if="item.children && item.active">
              <li
                class="subMneu"
                v-for="(child, index) in item.children"
                :key="index"
                @click="clickSubMenu(item,child.title)"
              >
                <router-link
                  class="menuB"
                  :to="{name:child.path,params:userName}"
                  :class="{ menu_active: child.active }"
                  >{{ child.title }}</router-link
                >
              </li>
            </ul>
          </li>
        </ul>
      </div>
代码分析:
  1. 针对菜单采用的是ul列表,然后采用v-for循环对菜单数据进行循环,菜单采用的是动态样式 : class

当点击菜单的path地址和菜单中的某个path相等时,动态渲染该样式。

  1. li包含<router-link>是为了当点击该菜单时,跳转到相应的内容
菜单的JS代码:

data( )函数数据:

export default {
  components: {

  },
  data() {
    return {
      menus: [
        { id: 1, title: "用户管理", path: "UserMannger", active: false },
        {
          id: 2,
          title: "商品管理",
          path: "goodsManger",
          active: false,
          children: [
            { id: 21, title: "增加商品", path: "addGoods", active: false },
          ],
        },
        { di: 3, title: "关于我们", path: "about", active: false },
      ],
      currentTag: "",
      tabName: "",
      flag2: true,
      // tabName:'用户管理',
      userName:''
    };
  },

JS代码

methods: {
    changeCheck(id) {

      const obj = this.menus.find((item) => item.id == id);
      this.menus.find((item) => {
        if (item.id == id) {
          item.active = !item.active;
          if (item.children) {
            item.children.active = !item.active;
          }         
        }
      });
      this.currentTag = obj.path;
    },
    clickSubMenu(main,val) {
      this.tabName = val
      main.children[0].active = !main.children[0].active
      main.active = !main.children[0].active;
    },
    backHome() {
      this.$router.push("/UserMannger/123");
    },
    getLogin2(val){
      this.userName = val
    },
    TabName(val){
      console.log(val);
      this.tabName = val
    }
  },
  created() {
    this.$bus.$on('toHome',this.getLogin2)
  },
};

方法中 changeCheck函数分析:

  1. 首先先接收点击菜单的id,对menus数字进行遍历,当id相同时,将该菜单的active属性进行动态改变,这样做是为了动态切换样式。在遍历中还要对子菜单进行判断,如果有子菜单则将该子菜单的active属性改变

方法中 clickSubMneu函数分析:

  1. 因为该方法是当点击子菜单触发此事件,触发事件时传入该子菜单的一级菜单,然后将该菜单的子菜单的active属性进行动态改变,并且将主菜单的active属性始终与子菜单保持相反。
  2. 因为这里只设置了一个子菜单所以下标为0,当需要设置多个子菜单时,还需要传入index和子菜单的index然后进行判断方法和对一级菜单的判断相同。
CSS代码
当点击子菜单的a标签的公共样式
.menu_active {
  color: red;
  display: block;
  width: 100%;
  text-decoration: none;
  color: rgb(255, 208, 75);
  background-color: #409eff;
}

菜单修饰
.nav {
      height: 100%;
      flex-grow: 1;
      background-color: #001529;
      ul {
        .mainMenu {
          margin-top: 20px;
          width: 100%;
          text-align: center;
          line-height: 50px;
          color: white;

          .mainA {
            display: block;
            width: 100%;
            text-decoration: none;
            color: white;
            &:hover {
              background-color: #409eff;
            }
            &:active {
              color: rgb(255, 208, 75);
            }
          }
        }
      }
    }

这里采用的SCSS预编译语言:

在菜单css修饰中需要注意的是,一定要给一级菜单和二级菜单起名字,即使scss能够嵌套,依然会发生样式穿透的bug,所以针对一级菜单和二级菜单的样式进行单独修饰。

这里还需要知道的是 scss中有 :active和 : hover 的伪类用法,前者是当点击时触发该样式,后者是鼠标悬浮时触发的样式。