UNPKG

vxe-pc-ui

Version:
474 lines (473 loc) 14.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _vue = require("vue"); var _xeUtils = _interopRequireDefault(require("xe-utils")); var _ui = require("../../ui"); var _dom = require("../../ui/src/dom"); var _utils = require("../../ui/src/utils"); var _vn = require("../../ui/src/vn"); var _loading = _interopRequireDefault(require("../../loading/src/loading")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = (0, _vue.defineComponent)({ name: 'VxeMenu', props: { modelValue: [String, Number], expandAll: Boolean, collapsed: { type: Boolean, default: null }, collapseFixed: Boolean, loading: Boolean, options: { type: Array, default: () => [] }, size: { type: String, default: () => (0, _ui.getConfig)().image.size || (0, _ui.getConfig)().size } }, emits: ['update:modelValue', 'click'], setup(props, context) { const { emit, slots } = context; const xID = _xeUtils.default.uniqueId(); const $xeLayoutAside = (0, _vue.inject)('$xeLayoutAside', null); const refElem = (0, _vue.ref)(); const refCollapseElem = (0, _vue.ref)(); const { computeSize } = (0, _ui.useSize)(props); const reactData = (0, _vue.reactive)({ initialized: !!props.collapsed, isEnterCollapse: false, collapseStyle: {}, collapseZindex: 0, activeName: props.modelValue, menuList: [], itemHeight: 1 }); const refMaps = { refElem }; const computeIsCollapsed = (0, _vue.computed)(() => { const { collapsed } = props; if (_xeUtils.default.isBoolean(collapsed)) { return collapsed; } if ($xeLayoutAside) { return !!$xeLayoutAside.props.collapsed; } return false; }); const computeCollapseWidth = (0, _vue.computed)(() => { let collapseWidth = ''; if ($xeLayoutAside) { collapseWidth = $xeLayoutAside.props.collapseWidth || ''; } return collapseWidth; }); const computeCollapseEnterWidth = (0, _vue.computed)(() => { let width = ''; if ($xeLayoutAside) { width = $xeLayoutAside.props.width || ''; } return width; }); const computeMaps = { computeSize }; const $xeMenu = { xID, props, context, reactData, getRefMaps: () => refMaps, getComputeMaps: () => computeMaps }; const getMenuTitle = item => { return `${item.title || item.name}`; }; const updateZindex = () => { if (reactData.collapseZindex < (0, _utils.getLastZIndex)()) { reactData.collapseZindex = (0, _utils.nextZIndex)(); } }; const updateActiveMenu = isDefExpand => { const { activeName } = reactData; _xeUtils.default.eachTree(reactData.menuList, (item, index, items, path, parent, nodes) => { if (item.itemKey === activeName) { nodes.forEach(obj => { obj.isActive = true; if (isDefExpand) { obj.isExpand = true; } }); item.isExactActive = true; } else { item.isExactActive = false; item.isActive = false; } }, { children: 'childList' }); }; const updateMenuConfig = () => { const { options, expandAll } = props; reactData.menuList = _xeUtils.default.mapTree(options, (item, index, items, path, parent) => { const objItem = Object.assign(Object.assign({}, item), { parentKey: parent ? parent.name || path.slice(0, path.length - 1).join(',') : '', level: path.length, itemKey: item.name || path.join(','), isExactActive: false, isActive: false, isExpand: _xeUtils.default.isBoolean(item.expanded) ? item.expanded : !!expandAll, hasChild: item.children && item.children.length > 0 }); return objItem; }, { children: 'children', mapChildren: 'childList' }); }; const updateCollapseStyle = () => { const { collapseFixed } = props; if (collapseFixed) { (0, _vue.nextTick)(() => { const { isEnterCollapse } = reactData; const isCollapsed = computeIsCollapsed.value; const collapseEnterWidth = computeCollapseEnterWidth.value; const collapseWidth = computeCollapseWidth.value; const el = refElem.value; if (el) { const clientRect = el.getBoundingClientRect(); const parentNode = el.parentNode; reactData.collapseStyle = isCollapsed ? { top: (0, _dom.toCssUnit)(clientRect.top), left: (0, _dom.toCssUnit)(clientRect.left), height: (0, _dom.toCssUnit)(parentNode.clientHeight), width: isEnterCollapse ? collapseEnterWidth ? (0, _dom.toCssUnit)(collapseEnterWidth) : '' : collapseWidth ? (0, _dom.toCssUnit)(collapseWidth) : '', zIndex: reactData.collapseZindex } : {}; } }); } }; const handleCollapseMenu = () => { const { collapseFixed } = props; if (collapseFixed) { const { initialized } = reactData; const isCollapsed = computeIsCollapsed.value; if (isCollapsed) { if (!initialized) { reactData.initialized = true; (0, _vue.nextTick)(() => { const collapseEl = refCollapseElem.value; if (collapseEl) { document.body.appendChild(collapseEl); } }); } } reactData.isEnterCollapse = false; updateZindex(); updateCollapseStyle(); } }; const handleClickIconCollapse = (evnt, item) => { const { hasChild, isExpand } = item; if (hasChild) { evnt.stopPropagation(); evnt.preventDefault(); item.isExpand = !isExpand; } }; const emitModel = value => { reactData.activeName = value; emit('update:modelValue', value); }; const handleClickMenu = (evnt, item) => { const { itemKey, routerLink, hasChild } = item; if (routerLink) { emitModel(itemKey); handleMenuMouseleave(); } else { if (hasChild) { handleClickIconCollapse(evnt, item); } else { emitModel(itemKey); handleMenuMouseleave(); } } dispatchEvent('click', { menu: item }, evnt); }; const handleMenuMouseenter = () => { const { collapseStyle } = reactData; const collapseEnterWidth = computeCollapseEnterWidth.value; reactData.collapseStyle = Object.assign({}, collapseStyle, { width: collapseEnterWidth ? (0, _dom.toCssUnit)(collapseEnterWidth) : '' }); reactData.isEnterCollapse = true; }; const handleMenuMouseleave = () => { const { collapseStyle } = reactData; const el = refElem.value; reactData.collapseStyle = Object.assign({}, collapseStyle, { width: el ? (0, _dom.toCssUnit)(el.offsetWidth) : '' }); reactData.isEnterCollapse = false; }; const callSlot = (slotFunc, params) => { if (slotFunc) { if (_xeUtils.default.isString(slotFunc)) { slotFunc = slots[slotFunc] || null; } if (_xeUtils.default.isFunction(slotFunc)) { return (0, _vn.getSlotVNs)(slotFunc(params)); } } return []; }; const dispatchEvent = (type, params, evnt) => { emit(type, (0, _ui.createEvent)(evnt, { $menu: $xeMenu }, params)); }; const menuMethods = { dispatchEvent }; const menuPrivateMethods = {}; Object.assign($xeMenu, menuMethods, menuPrivateMethods); const renderMenuTitle = item => { const { icon, isExpand, hasChild, slots: itemSlots } = item; const optionSlot = itemSlots ? itemSlots.default : slots.option; const title = getMenuTitle(item); const isCollapsed = computeIsCollapsed.value; return [(0, _vue.h)('div', { class: 'vxe-menu--item-link-icon' }, icon ? [(0, _vue.h)('i', { class: icon })] : []), optionSlot ? (0, _vue.h)('div', { class: 'vxe-menu--item-custom-title' }, callSlot(optionSlot, { option: item, collapsed: isCollapsed })) : (0, _vue.h)('div', { class: 'vxe-menu--item-link-title', title }, title), hasChild ? (0, _vue.h)('div', { class: 'vxe-menu--item-link-collapse', onClick(evnt) { handleClickIconCollapse(evnt, item); } }, [(0, _vue.h)('i', { class: isExpand ? (0, _ui.getIcon)().MENU_ITEM_EXPAND_OPEN : (0, _ui.getIcon)().MENU_ITEM_EXPAND_CLOSE })]) : (0, _vue.createCommentVNode)()]; }; const renderDefaultChildren = item => { const { itemKey, level, hasChild, isActive, isExactActive, isExpand, routerLink, childList } = item; const { isEnterCollapse } = reactData; const isCollapsed = computeIsCollapsed.value; if (item.permissionCode) { if (!_ui.permission.checkVisible(item.permissionCode)) { return (0, _vue.createCommentVNode)(); } } return (0, _vue.h)('div', { key: itemKey, class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, { 'is--exact-active': isExactActive, 'is--active': isActive, 'is--expand': (!isCollapsed || isEnterCollapse) && isExpand }] }, [routerLink ? (0, _vue.h)((0, _vue.resolveComponent)('router-link'), { class: 'vxe-menu--item-link', to: routerLink, onClick(evnt) { handleClickMenu(evnt, item); } }, { default: () => renderMenuTitle(item) }) : (0, _vue.h)('div', { class: 'vxe-menu--item-link', onClick(evnt) { handleClickMenu(evnt, item); } }, renderMenuTitle(item)), hasChild ? (0, _vue.h)('div', { class: 'vxe-menu--item-group' }, childList.map(child => renderDefaultChildren(child))) : (0, _vue.createCommentVNode)()]); }; const renderCollapseChildren = item => { const { itemKey, level, hasChild, isActive, isExactActive, routerLink, childList } = item; if (item.permissionCode) { if (!_ui.permission.checkVisible(item.permissionCode)) { return (0, _vue.createCommentVNode)(); } } return (0, _vue.h)('div', { key: itemKey, class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, { 'is--exact-active': isExactActive, 'is--active': isActive }] }, [routerLink ? (0, _vue.h)((0, _vue.resolveComponent)('router-link'), { class: 'vxe-menu--item-link', to: routerLink, onClick(evnt) { handleClickMenu(evnt, item); } }, { default: () => renderMenuTitle(item) }) : (0, _vue.h)('div', { class: 'vxe-menu--item-link', onClick(evnt) { handleClickMenu(evnt, item); } }, renderMenuTitle(item)), hasChild ? (0, _vue.h)('div', { class: 'vxe-menu--item-group' }, childList.map(child => renderDefaultChildren(child))) : (0, _vue.createCommentVNode)()]); }; const renderVN = () => { const { loading } = props; const { initialized, menuList, collapseStyle, isEnterCollapse } = reactData; const vSize = computeSize.value; const isCollapsed = computeIsCollapsed.value; return (0, _vue.h)('div', { ref: refElem, class: ['vxe-menu', { [`size--${vSize}`]: vSize, 'is--collapsed': isCollapsed, 'is--loading': loading }] }, [(0, _vue.h)('div', { class: 'vxe-menu--item-list' }, menuList.map(child => isCollapsed ? renderCollapseChildren(child) : renderDefaultChildren(child))), initialized ? (0, _vue.h)('div', { ref: refCollapseElem, class: ['vxe-menu--collapse-wrapper', { [`size--${vSize}`]: vSize, 'is--collapsed': isCollapsed, 'is--enter': isEnterCollapse, 'is--loading': loading }], style: collapseStyle, onMouseenter: handleMenuMouseenter, onMouseleave: handleMenuMouseleave }, [isCollapsed ? (0, _vue.h)('div', { class: 'vxe-menu--item-list' }, menuList.map(child => renderDefaultChildren(child))) : (0, _vue.createCommentVNode)()]) : (0, _vue.createCommentVNode)(), /** * 加载中 */ (0, _vue.h)(_loading.default, { class: 'vxe-list-view--loading', modelValue: loading })]); }; const optFlag = (0, _vue.ref)(0); (0, _vue.watch)(() => props.options ? props.options.length : -1, () => { optFlag.value++; }); (0, _vue.watch)(() => props.options, () => { optFlag.value++; }); (0, _vue.watch)(optFlag, () => { updateMenuConfig(); updateActiveMenu(true); }); (0, _vue.watch)(() => props.modelValue, val => { reactData.activeName = val; }); (0, _vue.watch)(() => reactData.activeName, () => { updateActiveMenu(true); }); (0, _vue.watch)(computeIsCollapsed, () => { handleCollapseMenu(); }); (0, _vue.onMounted)(() => { _ui.globalEvents.on($xeMenu, 'resize', updateCollapseStyle); updateCollapseStyle(); }); (0, _vue.onBeforeUnmount)(() => { _ui.globalEvents.off($xeMenu, 'resize'); const collapseEl = refCollapseElem.value; if (collapseEl) { const parentNode = collapseEl.parentNode; if (parentNode) { parentNode.removeChild(collapseEl); } } }); updateMenuConfig(); updateActiveMenu(true); $xeMenu.renderVN = renderVN; return $xeMenu; }, render() { return this.renderVN(); } });