element-plus
Version:
A Component Library for Vue 3
1 lines • 16.9 kB
Source Map (JSON)
{"version":3,"file":"menu.mjs","sources":["../../../../../../packages/components/menu/src/menu.ts"],"sourcesContent":["import {\n defineComponent,\n getCurrentInstance,\n watch,\n computed,\n ref,\n provide,\n onMounted,\n h,\n withDirectives,\n reactive,\n nextTick,\n} from 'vue'\nimport { Resize } from '@element-plus/directives'\nimport ElIcon from '@element-plus/components/icon'\nimport { More } from '@element-plus/icons'\nimport Menubar from '@element-plus/utils/menu/menu-bar'\nimport { buildProps, definePropType, mutable } from '@element-plus/utils/props'\nimport { isString, isObject } from '@element-plus/utils/util'\nimport ElMenuCollapseTransition from './menu-collapse-transition.vue'\nimport ElSubMenu from './sub-menu'\nimport { useMenuCssVar } from './use-menu-css-var'\n\nimport type { MenuItemClicked, MenuProvider, SubMenuProvider } from './types'\nimport type { NavigationFailure, Router } from 'vue-router'\nimport type { VNode, ExtractPropTypes, VNodeNormalizedChildren } from 'vue'\n\nexport const menuProps = buildProps({\n mode: {\n type: String,\n values: ['horizontal', 'vertical'],\n default: 'vertical',\n },\n defaultActive: {\n type: String,\n default: '',\n },\n defaultOpeneds: {\n type: definePropType<string[]>(Array),\n default: () => mutable([] as const),\n },\n uniqueOpened: Boolean,\n router: Boolean,\n menuTrigger: {\n type: String,\n values: ['hover', 'click'],\n default: 'hover',\n },\n collapse: Boolean,\n backgroundColor: String,\n textColor: String,\n activeTextColor: String,\n collapseTransition: {\n type: Boolean,\n default: true,\n },\n ellipsis: {\n type: Boolean,\n default: true,\n },\n} as const)\nexport type MenuProps = ExtractPropTypes<typeof menuProps>\n\nconst checkIndexPath = (indexPath: unknown): indexPath is string[] =>\n Array.isArray(indexPath) && indexPath.every((path) => isString(path))\n\nexport const menuEmits = {\n close: (index: string, indexPath: string[]) =>\n isString(index) && checkIndexPath(indexPath),\n\n open: (index: string, indexPath: string[]) =>\n isString(index) && checkIndexPath(indexPath),\n\n select: (\n index: string,\n indexPath: string[],\n item: MenuItemClicked,\n routerResult?: Promise<void | NavigationFailure>\n ) =>\n isString(index) &&\n checkIndexPath(indexPath) &&\n isObject(item) &&\n (routerResult === undefined || routerResult instanceof Promise),\n}\nexport type MenuEmits = typeof menuEmits\n\nexport default defineComponent({\n name: 'ElMenu',\n\n props: menuProps,\n emits: menuEmits,\n\n setup(props, { emit, slots, expose }) {\n const instance = getCurrentInstance()!\n const router = instance.appContext.config.globalProperties.$router as Router\n const menu = ref<HTMLUListElement>()\n\n // data\n const openedMenus = ref<MenuProvider['openedMenus']>(\n props.defaultOpeneds && !props.collapse\n ? props.defaultOpeneds.slice(0)\n : []\n )\n const activeIndex = ref<MenuProvider['activeIndex']>(props.defaultActive)\n const items = ref<MenuProvider['items']>({})\n const subMenus = ref<MenuProvider['subMenus']>({})\n\n const alteredCollapse = ref(false)\n\n // computed\n const isMenuPopup = computed<MenuProvider['isMenuPopup']>(() => {\n return (\n props.mode === 'horizontal' ||\n (props.mode === 'vertical' && props.collapse)\n )\n })\n\n // methods\n const initMenu = () => {\n const activeItem = activeIndex.value && items.value[activeIndex.value]\n if (!activeItem || props.mode === 'horizontal' || props.collapse) return\n\n const indexPath = activeItem.indexPath\n\n // 展开该菜单项的路径上所有子菜单\n // expand all subMenus of the menu item\n indexPath.forEach((index) => {\n const subMenu = subMenus.value[index]\n subMenu && openMenu(index, subMenu.indexPath)\n })\n }\n\n const openMenu: MenuProvider['openMenu'] = (index, indexPath) => {\n if (openedMenus.value.includes(index)) return\n // 将不在该菜单路径下的其余菜单收起\n // collapse all menu that are not under current menu item\n if (props.uniqueOpened) {\n openedMenus.value = openedMenus.value.filter((index: string) =>\n indexPath.includes(index)\n )\n }\n openedMenus.value.push(index)\n emit('open', index, indexPath)\n }\n\n const closeMenu: MenuProvider['closeMenu'] = (index, indexPath) => {\n const i = openedMenus.value.indexOf(index)\n if (i !== -1) {\n openedMenus.value.splice(i, 1)\n }\n emit('close', index, indexPath)\n }\n\n const handleSubMenuClick: MenuProvider['handleSubMenuClick'] = ({\n index,\n indexPath,\n }) => {\n const isOpened = openedMenus.value.includes(index)\n\n if (isOpened) {\n closeMenu(index, indexPath)\n } else {\n openMenu(index, indexPath)\n }\n }\n\n const handleMenuItemClick: MenuProvider['handleMenuItemClick'] = (\n menuItem\n ) => {\n if (props.mode === 'horizontal' || props.collapse) {\n openedMenus.value = []\n }\n\n const { index, indexPath } = menuItem\n if (index === undefined || indexPath === undefined) return\n\n if (props.router && router) {\n const route = menuItem.route || index\n const routerResult = router.push(route).then((res) => {\n if (!res) activeIndex.value = index\n return res\n })\n emit(\n 'select',\n index,\n indexPath,\n { index, indexPath, route },\n routerResult\n )\n } else {\n activeIndex.value = index\n emit('select', index, indexPath, { index, indexPath })\n }\n }\n\n const updateActiveIndex = (val: string) => {\n const itemsInData = items.value\n const item =\n itemsInData[val] ||\n (activeIndex.value && itemsInData[activeIndex.value]) ||\n itemsInData[props.defaultActive]\n\n if (item) {\n activeIndex.value = item.index\n initMenu()\n } else {\n // Can't find item when collapsing\n // and activeIndex shouldn't be changed when 'collapse' was changed.\n // Then reset 'alteredCollapse' immediately.\n if (!alteredCollapse.value) {\n activeIndex.value = undefined\n } else {\n alteredCollapse.value = false\n }\n }\n }\n const handleResize = () => {\n nextTick(() => instance.proxy!.$forceUpdate())\n }\n\n watch(\n () => props.defaultActive,\n (currentActive) => {\n if (!items.value[currentActive]) {\n activeIndex.value = ''\n }\n updateActiveIndex(currentActive)\n }\n )\n\n watch(items.value, () => initMenu())\n\n watch(\n () => props.collapse,\n (value, prev) => {\n if (value !== prev) {\n alteredCollapse.value = true\n }\n if (value) openedMenus.value = []\n }\n )\n\n // provide\n {\n const addSubMenu: MenuProvider['addSubMenu'] = (item) => {\n subMenus.value[item.index] = item\n }\n\n const removeSubMenu: MenuProvider['removeSubMenu'] = (item) => {\n delete subMenus.value[item.index]\n }\n\n const addMenuItem: MenuProvider['addMenuItem'] = (item) => {\n items.value[item.index] = item\n }\n\n const removeMenuItem: MenuProvider['removeMenuItem'] = (item) => {\n delete items.value[item.index]\n }\n provide<MenuProvider>(\n 'rootMenu',\n reactive({\n props,\n openedMenus,\n items,\n subMenus,\n activeIndex,\n isMenuPopup,\n\n addMenuItem,\n removeMenuItem,\n addSubMenu,\n removeSubMenu,\n openMenu,\n closeMenu,\n handleMenuItemClick,\n handleSubMenuClick,\n })\n )\n provide<SubMenuProvider>(`subMenu:${instance.uid}`, {\n addSubMenu,\n removeSubMenu,\n })\n }\n\n // lifecycle\n onMounted(() => {\n initMenu()\n if (props.mode === 'horizontal') {\n new Menubar(instance.vnode.el!)\n }\n })\n\n {\n const open = (index: string) => {\n const { indexPath } = subMenus.value[index]\n indexPath.forEach((i) => openMenu(i, indexPath))\n }\n expose({\n open,\n close: closeMenu,\n handleResize,\n })\n }\n\n const flattedChildren = (children: VNodeNormalizedChildren) => {\n const vnodes = Array.isArray(children) ? children : [children]\n const result: any[] = []\n vnodes.forEach((child: any) => {\n if (Array.isArray(child.children)) {\n result.push(...flattedChildren(child.children))\n } else {\n result.push(child)\n }\n })\n return result\n }\n\n const useVNodeResize = (vnode: VNode) =>\n props.mode === 'horizontal'\n ? withDirectives(vnode, [[Resize, handleResize]])\n : vnode\n return () => {\n let slot = slots.default?.() ?? []\n const vShowMore: VNode[] = []\n\n if (props.mode === 'horizontal' && menu.value) {\n const items = Array.from(menu.value?.childNodes ?? []).filter(\n (item) => item.nodeName !== '#text' || item.nodeValue\n ) as HTMLElement[]\n const originalSlot = flattedChildren(slot)\n const moreItemWidth = 64\n const paddingLeft = parseInt(\n getComputedStyle(menu.value).paddingLeft,\n 10\n )\n const paddingRight = parseInt(\n getComputedStyle(menu.value).paddingRight,\n 10\n )\n const menuWidth = menu.value.clientWidth - paddingLeft - paddingRight\n let calcWidth = 0\n let sliceIndex = 0\n items.forEach((item, index) => {\n calcWidth += item.offsetWidth || 0\n if (calcWidth <= menuWidth - moreItemWidth) {\n sliceIndex = index + 1\n }\n })\n const slotDefault = originalSlot.slice(0, sliceIndex)\n const slotMore = originalSlot.slice(sliceIndex)\n if (slotMore?.length && props.ellipsis) {\n slot = slotDefault\n vShowMore.push(\n h(\n ElSubMenu,\n {\n index: 'sub-menu-more',\n class: 'el-sub-menu__hide-arrow',\n },\n {\n title: () =>\n h(\n ElIcon,\n {\n class: ['el-sub-menu__icon-more'],\n },\n { default: () => h(More) }\n ),\n default: () => slotMore,\n }\n )\n )\n }\n }\n\n const ulStyle = useMenuCssVar(props)\n\n const resizeMenu = (vNode: VNode) =>\n props.ellipsis ? useVNodeResize(vNode) : vNode\n\n const vMenu = resizeMenu(\n h(\n 'ul',\n {\n key: String(props.collapse),\n role: 'menubar',\n ref: menu,\n style: ulStyle.value,\n class: {\n 'el-menu': true,\n 'el-menu--horizontal': props.mode === 'horizontal',\n 'el-menu--collapse': props.collapse,\n },\n },\n [...slot.map((vnode) => resizeMenu(vnode)), ...vShowMore]\n )\n )\n\n if (props.collapseTransition && props.mode === 'vertical') {\n return h(ElMenuCollapseTransition, () => vMenu)\n }\n\n return vMenu\n }\n },\n})\n"],"names":["Menubar","ElSubMenu","ElMenuCollapseTransition"],"mappings":"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"}