From 58ef1bbc645e6d8c056e58fa69ffe92ed1186982 Mon Sep 17 00:00:00 2001 From: augushong Date: Sat, 10 Oct 2026 14:26:51 +0000 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=85=A8=E9=83=A8=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E9=A1=B6=E9=83=A8=E9=9D=A2=E6=9D=BF=E4=B8=8E=E6=98=9F?= =?UTF-8?q?=E6=A0=87=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugs/lay-module/layuimini/layuimini.css | 5 + .../plugs/lay-module/layuimini/miniMenu.js | 116 ++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/public/static/plugs/lay-module/layuimini/layuimini.css b/public/static/plugs/lay-module/layuimini/layuimini.css index 46ece0a..4d0a0ff 100644 --- a/public/static/plugs/lay-module/layuimini/layuimini.css +++ b/public/static/plugs/lay-module/layuimini/layuimini.css @@ -1022,4 +1022,9 @@ .layuimini-star.layuimini-star-active { color: #ffb800; +} + +/* 面板打开期间收起「更多」hover 下拉(临时类由 openModulePanel/closeModulePanel 维护) */ +.layuimini-header-more-panelopen > .layui-nav-child { + display: none !important; } \ No newline at end of file diff --git a/public/static/plugs/lay-module/layuimini/miniMenu.js b/public/static/plugs/lay-module/layuimini/miniMenu.js index cfe3c6b..1596b48 100644 --- a/public/static/plugs/lay-module/layuimini/miniMenu.js +++ b/public/static/plugs/lay-module/layuimini/miniMenu.js @@ -8,6 +8,9 @@ // 菜单数据缓存(renderMultiModule 入口保存,收藏过滤与面板渲染复用;保存原 menuList 引用) menuData: [], + // 顶部「全部模块」面板 layer index(null=面板未打开) + modulePanelIndex: null, + /** * 菜单初始化 * @param options.menuList 菜单数据信息 @@ -238,6 +241,26 @@ miniMenu.syncHeaderActiveState(); }, + /** + * 头部模块 DOM 重排:头部 li 显示顺序跟随 sortModules(收藏置顶+原序回填),「更多」li 常驻末尾 + * 星标收藏切换后调用实现头部即时重排;移动 li 不改类名,激活态/折叠态由后续 relayout 重算 + */ + reorderHeaderMenu: function () { + var $headerMenu = $('.layuimini-menu-header-pc'); + var $more = $headerMenu.children('.layuimini-header-more'); + if (!$headerMenu.length || !$more.length) { + return; + } + var sortedMenuList = miniMenu.sortModules(miniMenu.menuData); + var moreEl = $more[0]; + miniMenu.each(sortedMenuList, function (index, menu) { + var li = document.getElementById('multi_module_' + miniMenu.menuData.indexOf(menu) + 'HeaderId'); + if (li) { + $headerMenu[0].insertBefore(li, moreEl); //依次前插到「更多」li 之前,形成排序后顺序 + } + }); + }, + /** * 头部模块宽度自适应折叠重算:累计宽度超出可用宽度的模块收纳进「更多」下拉 */ @@ -300,6 +323,64 @@ } }, + /** + * 顶部「全部模块」面板打开:menuData 经 sortModules 平铺为 tile(收藏置顶+回填序) + */ + openModulePanel: function () { + var me = this; + var favorites = me.getFavorites(); + var sortedMenuList = me.sortModules(me.menuData); + var tileHtml = ''; + me.each(sortedMenuList, function (index, menu) { + // data-header-id 按 menuList 原下标映射(排序只影响显示顺序,与头部 li id 分配规则一致);不带 data-menu,避免与 [data-menu] 委托双触发 + var originalIndex = me.menuData.indexOf(menu); + var starActive = favorites.indexOf(menu.title) !== -1 ? ' layuimini-star-active' : ''; + var icon = menu.icon ? menu.icon : ''; + tileHtml += '
' + + '' + + '
' + menu.title + '
' + + '' + + '
'; + }); + // 配色继承:非透明头部主题时同步头部背景/字色到面板根容器;透明主题(rgba(0,0,0,0))保留 CSS 白底深字兜底 + var panelStyle = ''; + var headerEl = $('.layui-header').first()[0]; + if (headerEl) { + var headerStyle = getComputedStyle(headerEl); + if (headerStyle.backgroundColor !== 'rgba(0, 0, 0, 0)') { + panelStyle = ' style="background-color:' + headerStyle.backgroundColor + ';color:' + headerStyle.color + ';"'; + } + } + // 打开期间收起「更多」hover 下拉,避免遮罩后方残留展开外观(关闭时移除) + $('.layuimini-header-more').addClass('layuimini-header-more-panelopen'); + me.modulePanelIndex = layer.open({ + type: 1, + title: '全部模块', + anim: 2, + offset: 't', + area: ['100%', 'auto'], + shade: 0.2, + shadeClose: true, + closeBtn: 0, + content: '
' + tileHtml + '
', + end: function () { + me.closeModulePanel(); //遮罩/切tile等 layer 原生关闭路径统一走清理 + } + }); + }, + + /** + * 顶部面板关闭:幂等(end 回调重入时 index 已置 null,重复调用安全) + */ + closeModulePanel: function () { + var index = miniMenu.modulePanelIndex; + miniMenu.modulePanelIndex = null; + if (index) { + layer.close(index); + } + $('.layuimini-header-more').removeClass('layuimini-header-more-panelopen'); + }, + /** * 轻量防抖:delay 内重复触发只执行最后一次 */ @@ -404,6 +485,41 @@ setTimeout(miniMenu.relayoutHeaderMenu, 260); //左侧布局带 .2s 过渡,同步测量会读到中间值,等过渡结束再重算 layer.close(loading); }); + + /** + * 顶部「全部模块」面板:委托绑定一次即可(tile/星标均为动态 DOM,重渲染无需重绑) + */ + if (!miniMenu._panelListenerBound) { + miniMenu._panelListenerBound = true; + // 打开/切换面板:「更多」li 自身不带 data-menu,stopPropagation 隔离其他 body 委托 + $('body').on('click', '.layuimini-header-more > a', function (e) { + e.stopPropagation(); + if (miniMenu.modulePanelIndex) { + miniMenu.closeModulePanel(); + } else { + miniMenu.openModulePanel(); + } + }); + // ESC 关闭面板(layui layer 原生不支持 ESC,自实现;仅在面板存在时响应,不影响其他弹层) + $(document).on('keydown', function (e) { + if (e.keyCode === 27 && miniMenu.modulePanelIndex) { + miniMenu.closeModulePanel(); + } + }); + // tile 主体点击:触发真实头部 li(可见或折叠隐藏均可),走 [data-menu] 委托完整链路后关闭面板 + $('body').on('click', '.layuimini-module-panel-item', function () { + $('#' + $(this).attr('data-header-id')).trigger('click'); + layer.close(miniMenu.modulePanelIndex); + }); + // 星标点击:切换收藏 → 头部即时重排(重排序+折叠重算)→ 就地更新星标类名(面板保持打开,支持连续操作) + $('body').on('click', '.layuimini-module-panel-item .layuimini-star', function (e) { + e.stopPropagation(); //阻断冒泡,避免同时触发 tile 的切模块点击 + var isAdd = miniMenu.toggleFavorite($(this).closest('.layuimini-module-panel-item').attr('data-title')); + miniMenu.reorderHeaderMenu(); + miniMenu.relayoutHeaderMenu(); + $(this).toggleClass('layuimini-star-active', isAdd); + }); + } }, };