UNPKG

@arco-design/web-vue

Version:

Arco Design Vue 2.0: A Vue.js 3 UI Library

113 lines (112 loc) 4.48 kB
import { defineComponent, ref, onMounted, onUnmounted, createVNode, cloneVNode, mergeProps, createTextVNode } from "vue"; import ResizeObserver from "resize-observer-polyfill"; import { getStyle } from "../_utils/style.js"; import useMenuContext from "./hooks/use-menu-context.js"; import SubMenu from "./sub-menu.js"; import { unFragment } from "../_utils/vue-utils.js"; const OVERFLOW_THRESHOLD = 10; function getNodeWidth(el) { return el && +el.getBoundingClientRect().width.toFixed(2); } function translatePxToNumber(str) { const result = Number(str.replace("px", "")); return Number.isNaN(result) ? 0 : result; } var OverflowWrap = defineComponent({ name: "MenuOverflowWrap", setup(_, { slots }) { const menuContext = useMenuContext(); const overflowPrefixCls = `${menuContext.prefixCls}-overflow`; const overflowSubMenuClass = `${overflowPrefixCls}-sub-menu`; const overflowMenuItemClass = `${overflowPrefixCls}-hidden-menu-item`; const overflowSubMenuMirrorClass = `${overflowPrefixCls}-sub-menu-mirror`; const refWrapper = ref(); const lastVisibleIndex = ref(null); const refResizeObserver = ref(); function computeLastVisibleIndex() { const wrapperElement = refWrapper.value; const wrapperWidth = getNodeWidth(wrapperElement); const childNodeList = [].slice.call(wrapperElement.children); let menuItemIndex = 0; let currentRightWidth = 0; let overflowSubMenuWidth = 0; for (let i = 0; i < childNodeList.length; i++) { const node = childNodeList[i]; const classNames = node.className.split(" "); const isOverflowSubMenu = classNames.indexOf(overflowSubMenuClass) > -1; const isOverflowSubMenuMirror = classNames.indexOf(overflowSubMenuMirrorClass) > -1; if (isOverflowSubMenu) { continue; } const nodeWidth = getNodeWidth(node) + translatePxToNumber(getStyle(node, "marginLeft")) + translatePxToNumber(getStyle(node, "marginRight")); if (isOverflowSubMenuMirror) { overflowSubMenuWidth = nodeWidth; continue; } currentRightWidth += nodeWidth; if (currentRightWidth + overflowSubMenuWidth + OVERFLOW_THRESHOLD > wrapperWidth) { lastVisibleIndex.value = menuItemIndex - 1; return; } menuItemIndex++; } lastVisibleIndex.value = null; } onMounted(() => { computeLastVisibleIndex(); refResizeObserver.value = new ResizeObserver((entries) => { entries.forEach(computeLastVisibleIndex); }); if (refWrapper.value) { refResizeObserver.value.observe(refWrapper.value); } }); onUnmounted(() => { refResizeObserver.value && refResizeObserver.value.disconnect(); }); return () => { const renderSubMenu = (children, options) => { const { isMirror = false, props = {} } = options || {}; return createVNode(SubMenu, mergeProps({ "key": `__arco-menu-overflow-sub-menu${isMirror ? "-mirror" : ""}`, "class": isMirror ? overflowSubMenuMirrorClass : overflowSubMenuClass }, props), { title: () => createVNode("span", null, [createTextVNode("...")]), default: () => children }); }; const renderChildren = () => { var _a; const originChildren = ((_a = slots.default) == null ? void 0 : _a.call(slots)) || []; const children = unFragment(originChildren); let overflowSubMenu = null; const overflowSubMenuMirror = renderSubMenu(null, { isMirror: true }); const menuItems = children.map((child, index) => { const item = cloneVNode(child, lastVisibleIndex.value !== null && index > lastVisibleIndex.value ? { class: overflowMenuItemClass } : { class: "" }); if (lastVisibleIndex.value !== null && index === lastVisibleIndex.value + 1) { const overflowMenuItems = children.slice(index).map((child2) => cloneVNode(child2)); overflowSubMenu = renderSubMenu(overflowMenuItems); } return item; }); return [overflowSubMenuMirror, ...menuItems, overflowSubMenu]; }; return createVNode("div", { "class": `${overflowPrefixCls}-wrap`, "ref": refWrapper }, [renderChildren()]); }; } }); export { OverflowWrap as default };