在现代React应用中,可访问性是不可忽视的重要环节。useAccessibilityMenu Hook旨在为开发者提供一套完整的菜单组件可访问性解决方案。
核心功能
该Hook实现了键盘导航、焦点管理、Aria属性设置等核心可访问性功能。通过useRef和useEffect的组合,我们能够精确控制菜单项的焦点流转。
import { useState, useEffect, useRef } from 'react';
const useAccessibilityMenu = (items) => {
const [activeIndex, setActiveIndex] = useState(-1);
const menuRef = useRef(null);
// 键盘事件处理
const handleKeyDown = (event) => {
if (!menuRef.current) return;
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
setActiveIndex(prev => (prev + 1) % items.length);
break;
case 'ArrowUp':
event.preventDefault();
setActiveIndex(prev => (prev - 1 + items.length) % items.length);
break;
case 'Home':
event.preventDefault();
setActiveIndex(0);
break;
case 'End':
event.preventDefault();
setActiveIndex(items.length - 1);
break;
case 'Escape':
setActiveIndex(-1);
break;
default:
break;
}
};
// 焦点管理
useEffect(() => {
if (activeIndex >= 0 && menuRef.current) {
const activeElement = menuRef.current.children[activeIndex];
if (activeElement) {
activeElement.focus();
}
}
}, [activeIndex]);
// 初始化事件监听
useEffect(() => {
const menuElement = menuRef.current;
if (menuElement) {
menuElement.addEventListener('keydown', handleKeyDown);
return () => {
menuElement.removeEventListener('keydown', handleKeyDown);
};
}
}, [items.length]);
return {
menuRef,
activeIndex,
setActiveIndex,
getMenuItemProps: (index) => ({
tabIndex: index === activeIndex ? 0 : -1,
'aria-current': index === activeIndex ? 'true' : undefined
})
};
};
使用示例
const MenuComponent = () => {
const menuItems = ['首页', '产品', '关于我们', '联系我们'];
const { menuRef, activeIndex, getMenuItemProps } = useAccessibilityMenu(menuItems);
return (
<nav ref={menuRef} role="menubar">
{menuItems.map((item, index) => (
<button
key={index}
{...getMenuItemProps(index)}
onClick={() => console.log('点击:', item)}
>
{item}
</button>
))}
</nav>
);
};
性能优化
通过useCallback缓存事件处理器,避免不必要的重新渲染。同时使用useRef存储DOM引用,确保事件监听器的正确绑定与解绑。该Hook设计遵循React Hooks最佳实践,可有效提升菜单组件的可访问性与用户体验。

讨论