<script setup lang="ts">
import { computed } from 'vue';
import { type TreeMenuItem } from 'cube-front/core/stores/menu';
import SecondCascaderMenu from './components/SecondCascaderMenu.vue';
import { isChildMenu, hasChildren } from 'cube-front/core/utils/menuHelpers';
/**
* 层叠菜单组件Props接口定义
*/
interface CascaderMenuProps {
/** 菜单项 */
menu: TreeMenuItem;
/** 激活菜单项 */
activeMenu?: TreeMenuItem;
/** 当前鼠标悬浮菜单项 */
currentMenu?: TreeMenuItem;
/** 菜单点击回调函数 */
onMenuClick: (menu: TreeMenuItem) => void;
}
const props = defineProps<CascaderMenuProps>();
/** 一行显示菜单项数量 */
const menuItemColumns = 3;
/** 子菜单宽度 */
const subMenuWidth = 225;
/** 层叠菜单宽度 */
const subWidth = `${subMenuWidth * menuItemColumns}px`;
/** 导航栏宽度 */
const navWidth = '200px';
/** 是否折叠 */
const collapsed = false;
/**
* 计算处理后的子菜单列表
* 将没有子菜单的项目归类到一起,有子菜单的单独列出
*/
const children = computed(() => {
/** 无子菜单的菜单项 */
const noChildrenList = props.menu.children?.filter((item) => !hasChildren(item));
/** 有子菜单的菜单项 */
const childrenList: TreeMenuItem[] =
noChildrenList && noChildrenList.length > 0
? [
{
...props.menu,
children: noChildrenList,
},
]
: [];
props.menu.children?.forEach((item) => {
if (noChildrenList?.includes(item)) return;
childrenList.push(item);
});
return childrenList;
});
</script>
<template>
<div
:class="[
'menu-cascader',
{
'menu-cascader-current': currentMenu && isChildMenu(currentMenu, menu),
},
]"
:style="{
maxWidth: collapsed ? 'calc(100vw - 50px)' : `calc(100vw - ${navWidth})`,
}"
>
<SecondCascaderMenu
v-for="second in children"
:key="second.id"
:menu="second"
:width="subWidth"
:menuItemColumns="menuItemColumns"
:active-menu="activeMenu"
:on-menu-click="onMenuClick"
/>
</div>
</template>
<style lang="scss" scoped>
.menu-cascader {
position: relative;
box-sizing: border-box;
display: none;
height: 100%;
width: 675px;
max-width: calc(100vw - 200px);
overflow: hidden auto;
padding: 32px 16px 0;
z-index: 1100;
background: #fff;
border-left: 1px solid #f0f0f0;
/* 完全隐藏滚动条,但保留滚动功能 */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
}
.menu-cascader-current {
display: block;
}
</style>
|