在React应用中实现无障碍对话框组件时,useAccessibilityDialog Hook可以显著提升用户体验和可访问性。
核心功能
该Hook主要处理以下无障碍特性:
- 键盘导航(Tab/Shift+Tab)
- ESC键关闭对话框
- 焦点管理
- 背景滚动锁定
完整实现代码
import { useState, useEffect, useRef } from 'react';
export const useAccessibilityDialog = (isOpen, onClose) => {
const dialogRef = useRef(null);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
if (isOpen) {
setIsMounted(true);
// 锁定背景滚动
document.body.style.overflow = 'hidden';
// 设置初始焦点到对话框
setTimeout(() => {
if (dialogRef.current) {
dialogRef.current.focus();
}
}, 0);
} else {
// 恢复滚动
document.body.style.overflow = 'unset';
}
const handleKeyDown = (event) => {
if (event.key === 'Escape') {
onClose();
}
// 处理Tab键循环焦点
if (event.key === 'Tab') {
const focusableElements = dialogRef.current.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (event.shiftKey && document.activeElement === firstElement) {
lastElement.focus();
event.preventDefault();
} else if (!event.shiftKey && document.activeElement === lastElement) {
firstElement.focus();
event.preventDefault();
}
}
};
if (isOpen) {
document.addEventListener('keydown', handleKeyDown);
}
return () => {
document.removeEventListener('keydown', handleKeyDown);
document.body.style.overflow = 'unset';
};
}, [isOpen, onClose]);
const closeDialog = () => {
if (onClose) {
onClose();
}
};
return {
dialogRef,
isMounted,
closeDialog
};
};
使用示例
function MyDialog({ isOpen, onClose }) {
const { dialogRef, isMounted, closeDialog } = useAccessibilityDialog(isOpen, onClose);
if (!isMounted) return null;
return (
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
tabIndex="-1"
>
<h2 id="dialog-title">对话框标题</h2>
<p>对话框内容</p>
<button onClick={closeDialog}>关闭</button>
</div>
);
}
性能优化要点
- 使用useRef避免不必要的重渲染
- 合理的事件监听器清理
- 只在需要时添加键盘事件监听
通过该Hook,开发者可以快速构建符合WAI-ARIA标准的无障碍对话框组件。

讨论