UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

1 lines 10.2 kB
{"version":3,"file":"menu.mjs","sources":["../../../../../src/components/ivue-menu/menu.vue"],"sourcesContent":["<template>\r\n <ul :class=\"wrapperClasses\" :style=\"wrapperStyles\">\r\n <slot></slot>\r\n </ul>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { computed, onMounted, reactive, provide, watch, nextTick } from 'vue';\r\nimport { oneOf } from '../../utils/assist';\r\nimport { findComponentsUpward } from '../../utils/helpers';\r\n\r\n// ts\r\nimport { MenuContextKey, Props, Data } from './types/menu';\r\n\r\nconst prefixCls = 'ivue-menu';\r\n\r\nexport default {\r\n name: prefixCls,\r\n emits: ['on-select', 'on-open-change'],\r\n props: {\r\n /**\r\n * 主题,可选值为 light、dark、primary,其中 primary 只适用于 mode=\"horizontal\"\r\n *\r\n * @type {String}\r\n */\r\n theme: {\r\n type: String,\r\n validator(value: string) {\r\n return oneOf(value, ['light', 'dark', 'primary']);\r\n },\r\n default: 'light',\r\n },\r\n /**\r\n * 菜单类型,可选值为 horizontal(水平) 和 vertical(垂直)\r\n *\r\n * @type {String}\r\n */\r\n mode: {\r\n type: String,\r\n validator(value: string) {\r\n return oneOf(value, ['horizontal', 'vertical']);\r\n },\r\n default: 'vertical',\r\n },\r\n /**\r\n * 垂直宽度\r\n *\r\n * @type {String}\r\n */\r\n width: {\r\n type: String,\r\n default: '240px',\r\n },\r\n /**\r\n * 展开的 Submenu 的 name 集合\r\n *\r\n * @type {Array}\r\n */\r\n openNames: {\r\n type: Array,\r\n default: () => [],\r\n },\r\n /**\r\n * 激活菜单的 name 值\r\n *\r\n * @type {String | Number}\r\n */\r\n activeName: {\r\n type: [String, Number],\r\n },\r\n /**\r\n * 是否开启手风琴模式,开启后每次至多展开一个子菜单\r\n *\r\n * @type {Boolean}\r\n */\r\n accordion: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n },\r\n setup(props: Props, { emit }) {\r\n // data\r\n const data = reactive<Data>({\r\n /**\r\n * 展开的 Submenu 的 name 集合\r\n *\r\n * @type {Array}\r\n */\r\n openedNames: [],\r\n /**\r\n * 子菜单列表\r\n *\r\n * @type {Array}\r\n */\r\n menuItemList: [],\r\n /**\r\n * 下拉菜单列表\r\n *\r\n * @type {Array}\r\n */\r\n submenuList: [],\r\n /**\r\n * 当前激活的名称\r\n *\r\n * @type {String | Number}\r\n */\r\n currentActiveName: props.activeName,\r\n /**\r\n * 是否渲染完毕\r\n *\r\n * @type {Boolean}\r\n */\r\n ready: false,\r\n });\r\n\r\n // computed\r\n\r\n // 外部样式\r\n const wrapperClasses = computed(() => {\r\n let theme = props.theme;\r\n\r\n // 垂直 && primary\r\n if (props.mode === 'vertical' && props.theme === 'primary') {\r\n theme = 'light';\r\n }\r\n\r\n return [\r\n `${prefixCls}`,\r\n // 主题\r\n `${prefixCls}-${theme}`,\r\n {\r\n // 菜单类型\r\n [`${prefixCls}-${props.mode}`]: props.mode,\r\n },\r\n ];\r\n });\r\n\r\n // 外部样式\r\n const wrapperStyles = computed(() => {\r\n const style: {\r\n width?: string;\r\n } = {};\r\n\r\n // 垂直宽度\r\n if (props.mode === 'vertical') {\r\n style.width = props.width;\r\n }\r\n\r\n return style;\r\n });\r\n\r\n // methods\r\n\r\n // 激活当前子菜单\r\n const updateActiveName = (activeName?: string | number) => {\r\n // 是否有需要激活的name\r\n if (activeName) {\r\n data.currentActiveName = activeName;\r\n }\r\n\r\n // 没有菜单\r\n if (data.currentActiveName === undefined) {\r\n data.currentActiveName = -1;\r\n }\r\n\r\n // 子菜单列表\r\n data.submenuList\r\n .map((item) => item.submenu)\r\n .forEach((item) => {\r\n item.activeName(false);\r\n });\r\n\r\n // 菜单列表\r\n data.menuItemList.forEach((item) => {\r\n // 激活子菜单\r\n item.activeName(data.currentActiveName);\r\n });\r\n };\r\n\r\n // 激活子菜单\r\n const menuItemActive = (name: string | number) => {\r\n // 当前激活的名称\r\n data.currentActiveName = name;\r\n\r\n // 更新打开的菜单名称\r\n updateOpenKeys(name);\r\n\r\n emit('on-select', name);\r\n };\r\n\r\n // 发送选择事件\r\n const handleEmitSelectEvent = (name: string | number) => {\r\n emit('on-select', name);\r\n };\r\n\r\n // 更新打开的菜单名称\r\n const updateOpenKeys = (name) => {\r\n const names = [...data.openedNames];\r\n\r\n const index = names.indexOf(name);\r\n const submenuList = data.submenuList.map((item) => item.submenu);\r\n\r\n // 手风琴模式\r\n if (props.accordion) {\r\n // 关闭下拉菜单\r\n submenuList.forEach((item) => {\r\n item.data.opened = false;\r\n });\r\n }\r\n\r\n // 开的 Submenu 的 name 集合 有当前菜单\r\n if (index >= 0) {\r\n let currentSubmenu = null;\r\n\r\n // 关闭当前子菜单\r\n submenuList.forEach((item) => {\r\n if (item.name === name) {\r\n currentSubmenu = item;\r\n\r\n item.data.opened = false;\r\n }\r\n });\r\n\r\n if (currentSubmenu) {\r\n // 打开当前组件子菜单\r\n findComponentsUpward(currentSubmenu, 'ivue-menu-submenu').forEach(\r\n (item) => {\r\n item.data.opened = true;\r\n }\r\n );\r\n }\r\n\r\n // 子菜单列表全部关闭\r\n currentSubmenu.data.childSubmenuList\r\n .map((item) => item.submenu)\r\n .forEach((item) => {\r\n item.data.opened = false;\r\n });\r\n }\r\n // 没有当前菜单\r\n else {\r\n // 手风琴模式\r\n if (props.accordion) {\r\n let currentSubmenu = null;\r\n\r\n // 打开当前子菜单\r\n submenuList.forEach((item) => {\r\n if (item.name === name) {\r\n currentSubmenu = item;\r\n\r\n item.data.opened = true;\r\n }\r\n });\r\n\r\n if (currentSubmenu) {\r\n findComponentsUpward(currentSubmenu, 'ivue-menu-submenu').forEach(\r\n (item) => {\r\n item.data.opened = true;\r\n }\r\n );\r\n }\r\n } else {\r\n // 打开子菜单\r\n const submenuList = data.submenuList.map((item) => item.submenu);\r\n\r\n submenuList.forEach((item) => {\r\n if (item.name === name) {\r\n item.data.opened = true;\r\n }\r\n });\r\n }\r\n }\r\n\r\n // 获取当前打开的子菜单\r\n const openedNames = submenuList\r\n .filter((item) => item.data.opened)\r\n .map((item) => item.name);\r\n\r\n // 展开的 Submenu 的 name 集合\r\n data.openedNames = [...openedNames];\r\n\r\n // 当前展开的 Submenu 的 name 值数组\r\n emit('on-open-change', openedNames);\r\n };\r\n\r\n // 选择当前菜单\r\n const handleMenuItemSelect = (name: string | number) => {\r\n data.currentActiveName = name;\r\n\r\n emit('on-select', name);\r\n };\r\n\r\n // 展开子菜单\r\n const updateOpened = (openedNames?: any[]) => {\r\n // 是否有需要激活的菜单\r\n if (openedNames) {\r\n data.openedNames = openedNames;\r\n }\r\n\r\n const items = data.submenuList.map((item) => item.submenu);\r\n\r\n if (items.length) {\r\n items.forEach((item) => {\r\n // 展开子菜单\r\n if (data.openedNames.indexOf(item.name) > -1) {\r\n item.data.opened = true;\r\n }\r\n // 关闭子菜单\r\n else {\r\n item.data.opened = false;\r\n }\r\n });\r\n }\r\n };\r\n\r\n // provide\r\n\r\n provide(\r\n MenuContextKey,\r\n reactive({\r\n data,\r\n mode: props.mode,\r\n menuItemActive,\r\n handleEmitSelectEvent,\r\n updateOpenKeys,\r\n handleMenuItemSelect,\r\n })\r\n );\r\n\r\n // watch\r\n\r\n // 监听激活菜单的 name 值\r\n watch(\r\n () => props.activeName,\r\n (value) => {\r\n data.currentActiveName = value;\r\n }\r\n );\r\n\r\n // 监听当前激活的名称\r\n watch(\r\n () => data.currentActiveName,\r\n () => {\r\n updateActiveName();\r\n }\r\n );\r\n\r\n // 监听展开的 Submenu 的 name 集合\r\n watch(\r\n () => props.openNames,\r\n (value) => {\r\n data.openedNames = value;\r\n\r\n // 展开菜单\r\n updateOpened();\r\n }\r\n );\r\n\r\n // onMounted\r\n onMounted(() => {\r\n // 展开的 Submenu 的 name 集合\r\n data.openedNames = [...props.openNames];\r\n\r\n // 展开菜单\r\n updateOpened();\r\n\r\n nextTick(() => {\r\n // 激活子菜单\r\n updateActiveName();\r\n\r\n // 渲染完成\r\n data.ready = true;\r\n });\r\n });\r\n\r\n return {\r\n prefixCls,\r\n\r\n // data\r\n data,\r\n\r\n // computed\r\n wrapperClasses,\r\n wrapperStyles,\r\n updateOpenKeys,\r\n updateOpened,\r\n updateActiveName,\r\n };\r\n },\r\n};\r\n</script>\r\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle"],"mappings":";;;;AACY,SAAA,YAAA,IAAE,EAAA,MAAA,EAAc,MAAA,EAAA,MAAA,EAAA,OAAA,QAAA,EAAA;AAAQ,EAAA,OAAAA,SAAA,EAAA,EAAAC,kBAAA,CAAE,IAAa,EAAA;AAAA,IAAA,KAAA,EAAAC,cAAA,CAAA,MAAA,CAAA,cAAA,CAAA;AAAA,IAC/C,KAAA,EAAaC,cAAA,CAAA,MAAA,CAAA,aAAA,CAAA;AAAA,GAAA,EAAA;AAAA;;;;;;;"}