You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
10 KiB

/**
* Navigation Menu Block JavaScript
* 导航菜单区块交互功能
*/
(function($) {
'use strict';
// 导航菜单类
class NavigationMenu {
constructor(element) {
this.element = element;
this.menuList = element.querySelector('.navigation-menu-list');
this.dropdownItems = element.querySelectorAll('.has-dropdown');
this.isMobile = window.innerWidth <= 768;
this.init();
}
init() {
this.setupDropdowns();
this.setupKeyboardNavigation();
this.setupMobileHandling();
this.setupResizeHandler();
this.setupClickOutside();
}
// 设置下拉菜单功能
setupDropdowns() {
this.dropdownItems.forEach(item => {
const link = item.querySelector('a');
const submenu = item.querySelector('.sub-menu');
if (!submenu) return;
// 鼠标悬停事件
item.addEventListener('mouseenter', () => {
if (!this.isMobile) {
this.showSubmenu(submenu);
}
});
item.addEventListener('mouseleave', () => {
if (!this.isMobile) {
this.hideSubmenu(submenu);
}
});
// 点击事件(移动端)
link.addEventListener('click', (e) => {
if (this.isMobile) {
e.preventDefault();
this.toggleSubmenu(submenu);
}
});
// 添加ARIA属性
link.setAttribute('aria-haspopup', 'true');
link.setAttribute('aria-expanded', 'false');
submenu.setAttribute('aria-hidden', 'true');
});
}
// 显示子菜单
showSubmenu(submenu) {
submenu.style.opacity = '1';
submenu.style.visibility = 'visible';
submenu.style.transform = 'translateY(0)';
submenu.setAttribute('aria-hidden', 'false');
const parentLink = submenu.parentElement.querySelector('a');
if (parentLink) {
parentLink.setAttribute('aria-expanded', 'true');
}
}
// 隐藏子菜单
hideSubmenu(submenu) {
submenu.style.opacity = '0';
submenu.style.visibility = 'hidden';
submenu.style.transform = 'translateY(-10px)';
submenu.setAttribute('aria-hidden', 'true');
const parentLink = submenu.parentElement.querySelector('a');
if (parentLink) {
parentLink.setAttribute('aria-expanded', 'false');
}
}
// 切换子菜单显示状态
toggleSubmenu(submenu) {
const isVisible = submenu.style.opacity === '1' ||
submenu.getAttribute('aria-hidden') === 'false';
if (isVisible) {
this.hideSubmenu(submenu);
} else {
// 先隐藏其他打开的子菜单
this.hideAllSubmenus();
this.showSubmenu(submenu);
}
}
// 隐藏所有子菜单
hideAllSubmenus() {
const allSubmenus = this.element.querySelectorAll('.sub-menu');
allSubmenus.forEach(submenu => {
this.hideSubmenu(submenu);
});
}
// 设置键盘导航
setupKeyboardNavigation() {
const menuLinks = this.element.querySelectorAll('a');
menuLinks.forEach((link, index) => {
link.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowDown':
e.preventDefault();
this.focusNextItem(menuLinks, index);
break;
case 'ArrowUp':
e.preventDefault();
this.focusPrevItem(menuLinks, index);
break;
case 'ArrowRight':
e.preventDefault();
this.openSubmenuOnFocus(link);
break;
case 'ArrowLeft':
e.preventDefault();
this.closeSubmenuOnFocus(link);
break;
case 'Escape':
e.preventDefault();
this.hideAllSubmenus();
link.blur();
break;
case 'Enter':
case ' ':
if (link.getAttribute('aria-haspopup') === 'true') {
e.preventDefault();
const submenu = link.parentElement.querySelector('.sub-menu');
if (submenu) {
this.toggleSubmenu(submenu);
}
}
break;
}
});
});
}
// 焦点移动到下一个项目
focusNextItem(items, currentIndex) {
const nextIndex = (currentIndex + 1) % items.length;
items[nextIndex].focus();
}
// 焦点移动到上一个项目
focusPrevItem(items, currentIndex) {
const prevIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1;
items[prevIndex].focus();
}
// 在焦点时打开子菜单
openSubmenuOnFocus(link) {
const submenu = link.parentElement.querySelector('.sub-menu');
if (submenu) {
this.showSubmenu(submenu);
const firstSubmenuLink = submenu.querySelector('a');
if (firstSubmenuLink) {
firstSubmenuLink.focus();
}
}
}
// 在焦点时关闭子菜单
closeSubmenuOnFocus(link) {
const parentItem = link.closest('.sub-menu');
if (parentItem) {
const parentLink = parentItem.parentElement.querySelector('a');
if (parentLink) {
this.hideSubmenu(parentItem);
parentLink.focus();
}
}
}
// 设置移动端处理
setupMobileHandling() {
// 移动端特殊处理逻辑
if (this.isMobile) {
this.element.classList.add('mobile-menu');
// 为移动端添加展开/收起按钮
this.dropdownItems.forEach(item => {
const link = item.querySelector('a');
const arrow = link.querySelector('.dropdown-arrow');
if (arrow) {
arrow.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
const submenu = item.querySelector('.sub-menu');
if (submenu) {
this.toggleSubmenu(submenu);
}
});
}
});
}
}
// 设置窗口大小改变处理
setupResizeHandler() {
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
const wasMobile = this.isMobile;
this.isMobile = window.innerWidth <= 768;
if (wasMobile !== this.isMobile) {
this.hideAllSubmenus();
if (this.isMobile) {
this.element.classList.add('mobile-menu');
} else {
this.element.classList.remove('mobile-menu');
}
}
}, 250);
});
}
// 设置点击外部关闭菜单
setupClickOutside() {
document.addEventListener('click', (e) => {
if (!this.element.contains(e.target)) {
this.hideAllSubmenus();
}
});
}
// 销毁实例
destroy() {
// 移除事件监听器
this.dropdownItems.forEach(item => {
const link = item.querySelector('a');
const submenu = item.querySelector('.sub-menu');
if (link && submenu) {
// 这里应该移除所有添加的事件监听器
// 为了简化,我们只是重置状态
this.hideSubmenu(submenu);
}
});
}
}
// 初始化所有导航菜单
function initNavigationMenus() {
const menuElements = document.querySelectorAll('.navigation-menu-block');
const menuInstances = [];
menuElements.forEach(element => {
const instance = new NavigationMenu(element);
menuInstances.push(instance);
});
return menuInstances;
}
// DOM加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initNavigationMenus);
} else {
initNavigationMenus();
}
// 为jQuery用户提供接口
if ($ && typeof $.fn !== 'undefined') {
$.fn.navigationMenu = function() {
return this.each(function() {
if (!$(this).data('navigation-menu')) {
const instance = new NavigationMenu(this);
$(this).data('navigation-menu', instance);
}
});
};
}
// 全局暴露NavigationMenu类
window.NavigationMenu = NavigationMenu;
})(typeof jQuery !== 'undefined' ? jQuery : undefined);