diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 568fcf9..97f42cc 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -113,7 +113,7 @@ export default class RightMenu { this.addEvent(window, 'resize', this.destroyMenu.bind(this)) // 页面点击时销毁菜单栏 this.addEvent(document, 'mousedown', (e) => { - const hasMenu = e['path']?.some((node: HTMLDivElement) => node === menu) + const hasMenu = (e['path'] || e.composedPath())?.some((node: HTMLDivElement) => node === menu) if (!hasMenu) this.destroyMenu() }) } @@ -278,13 +278,24 @@ export default class RightMenu { // 添加二级菜单 if (opt.children && opt.children.length) { const ul = this.renderMenu(opt.children) + const parentMouseLeaveListener = () => li.removeChild(ul) li.addEventListener('mouseenter', (e) => { li.appendChild(ul) + li.parentElement?.removeEventListener('mouseleave', parentMouseLeaveListener) layoutMenuPositionEffect(li, ul) }) li.addEventListener('mouseleave', (e: MouseEvent) => { if (!e['toElement']) return let curr = e['toElement'] + + if (li.parentElement && curr === li.parentElement && (e.offsetX < 0 || e.offsetX >= li.offsetWidth)) { + // fix 存在滚动条时,从左右两侧移入子菜单 + li.parentElement.addEventListener('mouseleave', parentMouseLeaveListener, { + once: true, + }) + return + } + while (curr) { // 如果路径里存在 ul 标签, 就不需要销毁 if (curr === ul) return diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 5529db7..bf50f88 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -110,9 +110,24 @@ export const layoutMenuPositionEffect = ( const layoutToTop = () => { let y = baseY - // 尝试向上布局,判断菜单最顶端是否超出屏幕上边缘(视窗高度) + // 尝试向上布局,判断菜单最底端是否超出屏幕下边缘(视窗高度) if (menu.offsetHeight + y > window.innerHeight) { - y = baseY + baseH - height + const topY = baseY + baseH - height + if (topY >= 0) { + // 可以向上布局 + y = topY + return y + } + // 上下都放不下时,使用向上、向下两种方式中更高的区域+滚动条的形式 + const bottomHeight = window.innerHeight - baseY + const topHeight = baseY + baseH + const isBottom = bottomHeight > topHeight + const menuHeight = Math.max(bottomHeight, topHeight) + const menuMaxHeight = Math.floor(menuHeight - 5) + y = isBottom ? baseY : baseY + baseH - menuMaxHeight + menu.style.maxHeight = `${menuMaxHeight}px` + menu.style.overflowY = 'auto' + return y } return y }