/** 菜单 处理 **/ (function(vc) { var vm = new Vue({ el: '#menu-nav', data: { menus: [], subMenus: [], curMenuName: '', logo: '', }, mounted: function() { this._initSysInfo(); //监听 菜单目录改变 document.body.addEventListener('loadMenu', function(_param) { vm.curMenuName = ''; vm.subMenus = []; vm.getMenus(_param.detail); }, false); // 点击页面空白处自动关闭二级菜单 document.addEventListener('click', (e) => { const menuNav = document.getElementById('menu-nav'); // 整个菜单区域(包含一级和二级) const flyoutMenu = document.querySelector('.vc-menu-sub.flyout'); // 如果点击的是菜单区域内部(一级菜单或二级菜单),不关闭 if (menuNav && menuNav.contains(e.target)) { return; } // 点击的是页面其他地方 → 关闭二级菜单 if (flyoutMenu && flyoutMenu.classList.contains('active')) { this._closeSubMenu(); } }); }, methods: { _initSysInfo: function () { let sysInfo = vc.getData("java110SystemInfo"); let _that = this; if (!sysInfo) { setTimeout(function () { sysInfo = vc.getData("java110SystemInfo"); _that.logo = sysInfo.systemSimpleTitle; }, 2000); return; } this.logo = sysInfo.systemSimpleTitle; }, _gotoIndex: function() { vc.jumpToPage("/") }, getMenus: function(_catalog) { let _param = { params: { caId: _catalog.caId, communityId: vc.getCurrentCommunity().communityId } } //发送get请求 vc.http.apiGet('/menu.listCatalogMenus', _param, function(json, res) { let _menuData = JSON.parse(json); if (_menuData.code != 0) { return; } let _menus = _menuData.data; if (_menus == null || _menus.length == 0) { return; } _menus.sort(function(a, b) { return a.seq - b.seq }); //var _currentMenusId = vc.getCurrentMenu() == null ? _menus[0].id : vc.getCurrentMenu(); //let _currentMenusId = _menus[0].id; vm.menus = vm.refreshMenuActive(_menus, ''); vc.setMenus(vm.menus); // vm.switchMenu(_menus[0]); }, function(errInfo, error) { console.log('请求失败处理'); } ); }, refreshMenuActive: function(jsonArray, _id) { for (var menuIndex = 0; menuIndex < jsonArray.length; menuIndex++) { if (jsonArray[menuIndex].hasOwnProperty('childs')) { let _childs = jsonArray[menuIndex].childs; _childs.sort(function(_child, _newChild) { return _child.seq - _newChild.seq }); jsonArray[menuIndex].childs = _childs; } if (_id === jsonArray[menuIndex].id) { //如果当前本身是打开状态,说明 需要关闭 jsonArray[menuIndex].active = true; continue; } jsonArray[menuIndex].active = false; } return jsonArray; }, switchMenu: function(_menu) { //设置菜单ID vc.setCurrentMenu(_menu.id); vm.menus = vm.refreshMenuActive(vm.menus, _menu.id); vc.setMenus(vm.menus); vm.subMenus = _menu.childs; vm.curMenuName = _menu.name; // 二级菜单样式调整 vm.$nextTick(() => { const activeItem = document.querySelector('.vc-menu-main li.active'); const flyoutMenu = document.querySelector('.vc-menu-sub.flyout'); const mainMenu = document.querySelector('.vc-menu-main'); // 一级菜单容器 if (activeItem && flyoutMenu && mainMenu) { const itemTop = activeItem.offsetTop; const itemHeight = activeItem.offsetHeight; const menuHeight = flyoutMenu.offsetHeight; const mainMenuRect = mainMenu.getBoundingClientRect(); const availableBottom = mainMenuRect.bottom - 20; // 距离视口底部留20px边距 // 理想位置:垂直居中对齐当前项 let desiredTop = itemTop + (itemHeight - menuHeight) / 2; // 限制:不能超出顶部 if (desiredTop < 10) { desiredTop = 10; } // 限制:底部不能超过一级菜单可见底部 const maxTop = window.innerHeight - menuHeight - 60; // 留出顶部导航和底部安全距 if (desiredTop > maxTop) { desiredTop = maxTop; } flyoutMenu.style.top = desiredTop + 'px'; flyoutMenu.classList.add('active'); } }); if (!_menu.childs || _menu.childs.length < 1) { return; } //选中第一个 vm._gotoPage(_menu.childs[0].href, _menu.childs[0].name); //vc._fix_height() }, miniMenu: function() { //菜单默认为打开方式 if (!vc.notNull(vc.getMenuState())) { vc.setMenuState('ON'); } if (vc.notNull(vc.getMenuState()) && vc.getMenuState() == 'ON') { return; } $("body").toggleClass("mini-navbar"); vc.setMenuState('OFF'); }, _gotoPage: function(_href, _tabName) { // 子菜单默认选中 this._setSelectedMenusChild(_href); if (_href.indexOf('?') > -1) { _href += ("&tab=" + _tabName) } else { _href += ("?tab=" + _tabName) } vc.jumpToPage(_href); }, // 子菜单默认选中 _setSelectedMenusChild(_href) { for (var menuIndex = 0; menuIndex < this.menus.length; menuIndex++) { if (this.menus[menuIndex].hasOwnProperty('childs')) { var _childs = this.menus[menuIndex].childs; for (var childIndex = 0; childIndex < _childs.length; childIndex++) { if (_href == _childs[childIndex].href) { this.menus[menuIndex].childs[childIndex].active = true; } else { this.menus[menuIndex].childs[childIndex].active = false; } } } } this.$forceUpdate(); }, _closeSubMenu: function() { vm.curMenuName = ''; vm.subMenus = []; vm.menus.forEach(item => { item.active = false; }); }, // 新增:鼠标进入一级菜单项 hoverMenu: function(_menu) { // 高亮当前一级菜单 this.menus = this.refreshMenuActive(this.menus, _menu.id); vc.setMenus(this.menus); // 显示对应的二级菜单 this.subMenus = _menu.childs || []; this.curMenuName = _menu.name; // Vue渲染完成后定位并显示二级菜单 this.$nextTick(() => { const hoveredItem = document.querySelector('.vc-menu-main li.active'); const flyoutMenu = document.querySelector('.vc-menu-sub.flyout'); if (hoveredItem && flyoutMenu) { const itemTop = hoveredItem.offsetTop; const itemHeight = hoveredItem.offsetHeight; const menuHeight = flyoutMenu.offsetHeight; // 垂直居中对齐当前项 let desiredTop = itemTop + (itemHeight - menuHeight) / 2; if (desiredTop < 10) desiredTop = 10; const maxTop = window.innerHeight - menuHeight - 60; if (desiredTop > maxTop) desiredTop = maxTop; flyoutMenu.style.top = desiredTop + 'px'; flyoutMenu.classList.add('active'); } }); }, // 新增:鼠标离开一级菜单项时隐藏二级菜单 leaveMenu: function() { // 延迟隐藏,防止鼠标快速移到二级菜单时闪烁 setTimeout(() => { const flyoutMenu = document.querySelector('.vc-menu-sub.flyout'); const menuNav = document.getElementById('menu-nav'); // 如果鼠标当前不在整个菜单区域内,才关闭 if (flyoutMenu && menuNav && !menuNav.matches(':hover')) { this.subMenus = []; this.curMenuName = ''; this.menus.forEach(item => item.active = false); flyoutMenu.classList.remove('active'); } }, 200); // 200ms 延迟,给用户时间把鼠标移到二级菜单上 }, // 鼠标在二级菜单上时保持打开 keepMenuOpen: function() { // 可以什么都不做,只是阻止 leaveMenu 的定时器触发关闭 // 实际通过 :hover 判断已足够 }, }, }); })(window.vc)