useAccessibilityDialog对话框Hook

健身生活志 +0/-0 0 0 正常 2025-12-24T07:01:19 React Hooks · 无障碍访问

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

性能优化要点

  1. 使用useRef避免不必要的重渲染
  2. 合理的事件监听器清理
  3. 只在需要时添加键盘事件监听

通过该Hook,开发者可以快速构建符合WAI-ARIA标准的无障碍对话框组件。

推广
广告位招租

讨论

0/2000