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
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); |