123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- <script setup lang="ts">
- import type { BaseMenu } from '@/types/Promotion/Menu'
- import { computed, nextTick, ref, watch } from 'vue'
- import { useRoute } from 'vue-router'
- import { useAttrs } from 'vue'
- import router from '@/router'
- import CIcon from '../cIcon/CIcon.vue'
- interface MenuProps {
- menuStyle?: string
- menuItemStyle?: string
- defaultActive?: string
- menuList: BaseMenu[]
- }
- const props = withDefaults(defineProps<MenuProps>(), {})
- const routes = useRoute()
- const attrs = useAttrs()
- const emits = defineEmits(['activeChange'])
- // 纵向菜单折叠,仅在mode为vertical时生效
- const isCollapse = ref(false)
- // 高亮菜单的name
- const highlightMenu = ref()
- /**
- * @description: 菜单项改变
- * @param {*} newVal
- * @return {*}
- */
- const changeSelect = (newVal: string) => {
- emits('activeChange', newVal)
- }
- /**
- * @description: 改变箭头颜色
- * @return {*}
- */
- const changeArrow = () => {
- nextTick(() => {
- // 只有被加上这两个特殊类的箭头才去处理
- let activeItem = document.querySelector(
- '.activeItem .el-sub-menu__icon-arrow',
- ) as HTMLElement
- let noActiveItem = document.querySelector(
- '.noActiveItem .el-sub-menu__icon-arrow',
- ) as HTMLElement
- if (activeItem) {
- activeItem.style.color = '#409eff'
- }
- if (noActiveItem) {
- noActiveItem.style.color = 'unset'
- }
- })
- }
- /**
- * @description: 根据当前路由,高亮父菜单
- * @return {*}
- */
- watch(
- () => routes.path,
- (newval: string) => {
- props.menuList.forEach(item => {
- let result = item.children?.find(child => child.path === newval)
- // 有可能该选项卡没有子菜单,但他本身也可以高亮
- if (result || item.path === newval) highlightMenu.value = item.name
- })
- // 去调整箭头颜色
- changeArrow()
- },
- { deep: true, immediate: true },
- )
- /**
- * @description: 在使用router模式下的默认选中
- * @return {*}
- */
- const routerDefaultActive = computed(() => {
- if (attrs.router) {
- let menuItem = props.menuList.find(item => {
- let basePath = item.path // 你可以动态设置这个值
- if (basePath) {
- const escapedBasePath = basePath.replace(/\//g, '\\/') // 转义斜杠
- const regex = new RegExp(`^${escapedBasePath}(?:\/.*)?$`)
- if (regex.test(routes.path)) return true
- }
- return false
- })
- return menuItem?.path
- } else {
- return ''
- }
- })
- </script>
- <template>
- <div
- class="menuContainer"
- :class="[
- $attrs.mode === 'vertical' ? 'verticalContainer' : 'horizontalContainer',
- $attrs.mode === 'vertical' ? 'borderR' : '',
- ]"
- >
- <el-menu
- v-bind="{ ...$attrs }"
- class="menu"
- :collapse="isCollapse"
- :style="menuStyle"
- :ellipsis="false"
- :default-active="
- props.defaultActive ? props.defaultActive : routerDefaultActive
- "
- @select="changeSelect"
- >
- <template v-for="menuItem in menuList" :key="menuItem.name">
- <!-- 有子菜单 -->
- <el-sub-menu
- v-if="menuItem.children"
- :class="
- highlightMenu === menuItem.name ? 'activeItem' : 'noActiveItem'
- "
- :index="menuItem.name"
- >
- <template #title>
- <CIcon
- v-if="menuItem.iconDefault && highlightMenu !== menuItem.name"
- :src="menuItem.iconDefault"
- class="menuIcon"
- ></CIcon>
- <CIcon
- v-if="menuItem.iconActive && highlightMenu === menuItem.name"
- class="menuIcon"
- :src="menuItem.iconActive"
- ></CIcon>
- <span
- class="menuTitle"
- :class="{ menuActiveColor: highlightMenu === menuItem.name }"
- >{{ menuItem.title }}</span
- >
- </template>
- <el-menu-item v-for="item in menuItem.children" :index="item.path">
- <CIcon
- class="menuChildIcon"
- v-if="item.iconDefault"
- :src="item.iconDefault"
- ></CIcon>
- <span>{{ item.title }}</span>
- </el-menu-item>
- </el-sub-menu>
- <!-- 无子菜单 -->
- <el-menu-item
- :style="menuItemStyle"
- :index="$attrs.router ? menuItem.path : menuItem.name"
- v-else
- >
- <CIcon
- class="menuIcon"
- v-if="menuItem.iconDefault"
- :src="menuItem.iconDefault"
- ></CIcon>
- <span>{{ menuItem.title }}</span>
- </el-menu-item>
- </template>
- </el-menu>
- <div
- v-if="$attrs.mode === 'vertical'"
- class="sideBarFold"
- @click="isCollapse = !isCollapse"
- :style="{ textAlign: isCollapse ? 'center' : 'right' }"
- >
- <el-icon class="icon" :size="20"><Fold /></el-icon>
- </div>
- </div>
- </template>
- <style scoped>
- .menuContainer {
- position: relative;
- height: 100%;
- }
- .borderR {
- border-right: 1px solid #e8eaec;
- }
- /* 垂直样式 */
- .verticalContainer {
- .menu {
- position: relative;
- height: calc(100% - 40px);
- /* min-width: 180px; */
- border-right: none;
- }
- .sideBarFold {
- position: relative;
- bottom: 0px;
- /* width: 100%; */
- height: 40px;
- line-height: 40px;
- margin-right: 6px;
- cursor: pointer;
- background-color: white;
- /* text-align: right; */
- }
- .menuIcon {
- margin-right: 5px;
- }
- .menuChildIcon {
- margin-right: 2px;
- }
- .menuActiveColor {
- color: #409eff;
- }
- .menuTitle {
- font-weight: 700;
- }
- }
- /* 水平样式 */
- .horizontalContainer {
- .menu {
- /* min-width: 0; */
- padding: 0 20px;
- }
- .sideBarFold {
- position: absolute;
- right: 20px;
- bottom: 20px;
- cursor: pointer;
- }
- }
- </style>
|