Vue2案例:封装动态的el-menu组件

2024-01-30 21:15:16 浏览数 (1)

前言

大家好,我是腾讯云开发者社区的 Front_Yue,本篇文章将介绍如何封装element-ui中动态的el-menu组件,希望能够对大家有所帮助。

在前端开发中,我们经常需要使用到菜单组件来实现页面的导航和功能选择。而在项目中我们经常会将Element-UI作为组件库来方便我们的开发。但是,在实际项目中,我们经常会遇到需要动态生成菜单的场景,这时候我们就需要对el-menu进行封装,以便于我们更加灵活地使用和定制。

一、el-menu的基本用法

在这里我们我们主要讲解el-menu的用法,不再对element-ui进行说明。

el-menu提供水平和垂直菜单组件,可以通过设置el-menu-item和el-submenu来生成菜单项和子菜单。下面是一个简单的el-menu示例:

代码语言:html复制
<template>
  <el-menu default-active="1" class="el-menu-vertical-demo">
    <el-menu-item index="1">
      <i class="el-icon-menu"></i>
      <span slot="title">菜单项1</span>
    </el-menu-item>
    <el-menu-item index="2">
      <i class="el-icon-menu"></i>
      <span slot="title">菜单项2</span>
    </el-menu-item>
    <el-submenu index="3">
      <template slot="title">
        <i class="el-icon-menu"></i>
        <span>子菜单1</span>
      </template>
      <el-menu-item index="3-1">子菜单项1</el-menu-item>
      <el-menu-item index="3-2">子菜单项2</el-menu-item>
    </el-submenu>
  </el-menu>
</template>

通过上面的代码,我们可以看到el-menu的基本用法。在el-menu中,我们可以设置default-active属性来指定默认选中的菜单项,class属性用于设置菜单的样式。

el-menu中,我们可以使用el-menu-itemel-submenu来生成菜单项和子菜单。其中,el-menu-item的index属性用于设置菜单项的唯一标识,slot="title"用于设置菜单项的标题,el-submenu中的template slot="title"用于设置子菜单的标题。在el-submenu中,我们可以使用el-menu-item来生成子菜单项。

二、封装动态el-menu

在实际项目开发中,我们经常需要动态生成菜单,而el-menu并没有提供直接的支持。因此,我们需要对el-menu进行封装,以便于我们更加灵活地使用和定制。

在封装el-menu之前,我们需要先明确一下需求。我们需要根据后台返回的菜单数据动态生成菜单,同时支持菜单项的选中和展开状态的保存。

1. 动态生成菜单

为了实现动态生成菜单,我们需要将菜单数据从后台获取到,并将其转换成el-menu所需的格式。通常情况下,我们可以将菜单数据的格式设计成如下所示:

代码语言:javascript复制
[
  {
    "id": 1,
    "name": "菜单1",
    "icon": "el-icon-menu",
    "url": "/menu1",
    "children": [
      {
        "id": 11,
        "name": "子菜单1-1",
        "icon": "",
        "url": "/menu1/1",
        "children": []
      },
      {
        "id": 12,
        "name": "子菜单1-2",
        "icon": "",
        "url": "/menu1/2",
        "children": []
      }
    ]
  },
  {
    "id": 2,
    "name": "菜单2",
    "icon": "el-icon-menu",
    "url": "/menu2",
    "children": []
  }
]

通过上面的数据格式,我们可以看到每个菜单项都包含了id、name、icon、url和children等属性。其中,id用于唯一标识菜单项,name用于设置菜单项的标题,icon用于设置菜单项的图标,url用于设置菜单项的链接地址,children用于设置子菜单项。通过这样的数据格式,我们可以很方便地生成el-menu所需的菜单项和子菜单项。

接下来,我们就可以开始封装el-menu了。我们可以将el-menu封装成一个组件,命名为MenuCom。在MenuCom中,我们可以通过props来接收菜单数据和默认选中的菜单项。

在MenuCom中,我们可以将菜单数据转换成el-menu所需的格式,并将其渲染成el-menu。在MenuCom中,我们需要通过watch来监听菜单数据和默认选中的菜单项的变化,以便于更新菜单的状态。

MenuCom的代码实现:

代码语言:html复制
<template>
  <el-menu :default-active="defaultActive" :unique-opened="true" class="el-menu-vertical-demo" :collapse="collapse">
    <template v-for="menu in menuData">
      <template v-if="menu.children && menu.children.length > 0">
        <el-submenu :index="menu.id" :key="menu.id">
          <template slot="title">
            <i :class="menu.icon"></i>
            <span>{{ menu.name }}</span>
          </template>
          <template v-for="subMenu in menu.children">
            <el-menu-item :index="subMenu.id" :key="subMenu.id">
              <i :class="subMenu.icon"></i>
              <span>{{ subMenu.name }}</span>
            </el-menu-item>
          </template>
        </el-submenu>
      </template>
      <template v-else>
        <el-menu-item :index="menu.id" :key="menu.id">
          <i :class="menu.icon"></i>
          <span>{{ menu.name }}</span>
        </el-menu-item>
      </template>
    </template>
  </el-menu>
</template>
代码语言:js复制
<script>
export default {
  name: 'MenuCom',
  props: {
    menuData: {
      type: Array,
      default: []
    },
    defaultActive: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      collapse: false
    }
  },
  watch: {
    menuData: {
      handler() {
        this.$nextTick(() => {
          this.$refs.menu.updateOpened()
        })
      },
      deep: true
    },
    defaultActive() {
      this.$nextTick(() => {
        this.$refs.menu.updateActiveName()
      })
    }
  }
}
</script>

在MenuCom中,我们首先使用el-menu来渲染菜单,通过default-active属性来设置默认选中的菜单项,通过unique-opened属性来设置只展开一个子菜单。

在MenuCom中,我们使用v-for来遍历菜单数据,通过v-if和v-else来判断菜单项是菜单还是子菜单。j接下来,我们使用el-submenu来生成子菜单,通过template slot="title"来设置子菜单的标题,通过v-for来遍历子菜单项。

在MenuCom中,我们使用el-menu-item来生成菜单项,通过index属性来设置菜单项的唯一标识。在MenuCom中,我们使用watch来监听菜单数据和默认选中的菜单项的变化,以便于更新菜单的状态。

2. 选中和展开状态的保存

作为动态菜单,最重要的是,在封装el-menu时,我们需要支持菜单项的选中和展开状态的保存。在el-menu中,我们可以通过default-active属性来设置默认选中的菜单项,但是这种方式只能在页面刷新前生效,无法保存选中状态。因此,我们需要使用状态管理工具Vuex来保存菜单项的选中和展开状态。

Vuex中,我们可以使用state来保存菜单项的选中和展开状态,使用mutation来更新菜单项的选中和展开状态,使用getter来获取菜单项的选中和展开状态。

在MenuCom中,我们可以通过Vuex来获取菜单项的选中和展开状态,并将其传递给el-menu。当菜单项被选中或展开时,我们可以通过mutation来更新菜单项的选中和展开状态。

下面是Vuex的代码实现:

代码语言:javascript复制
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  activeMenu: '',
  openedMenus: []
}

const mutations = {
  setActiveMenu(state, activeMenu) {
    state.activeMenu = activeMenu
  },
  setOpenedMenus(state, openedMenus) {
    state.openedMenus = openedMenus
  }
}

const getters = {
  activeMenu: state => state.activeMenu,
  openedMenus: state => state.openedMenus
}

export default new Vuex.Store({
  state,
  mutations,
  getters
})

Vuex中,我们首先定义了state来保存菜单项的选中和展开状态。

mutations中,我们定义了setActiveMenusetOpenedMenus来更新菜单项的选中和展开状态。

getters中,我们定义了activeMenuopenedMenus来获取菜单项的选中和展开状态。

MenuCom完整代码示例:

代码语言:html复制
<template>
  <el-menu :default-active="activeMenu" :default-openeds="openedMenus" class="el-menu-vertical-demo" :collapse="collapse">
    <template v-for="menu in menuData">
      <template v-if="menu.children && menu.children.length > 0">
        <el-submenu :index="menu.id" :key="menu.id" @click="handleSubmenuClick(menu.id)">
          <template slot="title">
            <i :class="menu.icon"></i>
            <span>{{ menu.name }}</span>
          </template>
          <template v-for="subMenu in menu.children">
            <el-menu-item :index="subMenu.id" :key="subMenu.id" @click="handleMenuItemClick(subMenu.id)">
              <i :class="subMenu.icon"></i>
              <span>{{ subMenu.name }}</span>
            </el-menu-item>
          </template>
        </el-submenu>
      </template>
      <template v-else>
        <el-menu-item :index="menu.id" :key="menu.id" @click="handleMenuItemClick(menu.id)">
          <i :class="menu.icon"></i>
          <span>{{ menu.name }}</span>
        </el-menu-item>
      </template>
    </template>
  </el-menu>
</template>
代码语言:js复制
<script>
import { mapGetters, mapMutations } from 'vuex'

export default {
  name: 'MenuCom',
  props: {
    menuData: {
      type: Array,
      default: []
    }
  },
  data() {
    return {
      collapse: false
    }
  },
  computed: {
    ...mapGetters(['activeMenu', 'openedMenus'])
  },
  methods: {
    ...mapMutations(['setActiveMenu', 'setOpenedMenus']),
    handleMenuItemClick(index) {
      this.setActiveMenu(index)
    },
    handleSubmenuClick(index) {
      const openedMenus = this.openedMenus.slice()
      const indexInOpenedMenus = openedMenus.indexOf(index)
      if (indexInOpenedMenus === -1) {
        openedMenus.push(index)
      } else {
        openedMenus.splice(indexInOpenedMenus, 1)
      }
      this.setOpenedMenus(openedMenus)
    }
  }
}
</script>

在MenuCom中,我们首先使用Vuex来获取菜单项的选中和展开状态,同时我们使用@click来监听菜单项的点击事件,当菜单项被选中时,通过mutation来更新菜单项的选中状态。同理,使用@click来监听子菜单的点击事件,当子菜单被展开或收起时,我们通过mutation来更新菜单项的展开状态。

总结

本篇文章介绍了如何封装成动态的el-menu组件,文章介绍了组件初始示例,到如何根据动态菜单数据封装动态组件,我们通过封装组件,来提高在项目中的开发效率。通过本篇博客的学习,我们可以更好地理解Vue.js和Element UI的使用,以及如何封装组件来提高代码的复用性和可维护性。

最后,感谢腾讯云开发者社区小伙伴的陪伴,如果你喜欢我的博客内容,认可我的观点和经验分享,请点赞、收藏和评论,这将是对我最大的鼓励和支持。同时,也欢迎大家提出宝贵的意见和建议,让我能够更好地改进和完善我的博客。谢谢!

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

0 人点赞