"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > إنشاء شريط قوائم تنقل يمكن الوصول إليه باستخدام React Hooks

إنشاء شريط قوائم تنقل يمكن الوصول إليه باستخدام React Hooks

تم النشر بتاريخ 2024-08-25
تصفح:890

Building an Accessible Navigation Menubar with React Hooks

تم النشر بالخطأ! يرجى العودة لاحقًا للحصول على المزيد!

مقدمة

إن إنشاء تطبيقات ويب يمكن الوصول إليها ليس مجرد ممارسة جيدة - بل هو ضرورة الآن. لقد أتيحت لي الفرصة مؤخرًا لإنشاء شريط قوائم للتنقل مع التركيز على a11y. أثناء قيامي بالبحث، أدركت كيف أن معظم أشرطة القوائم المتوفرة لا تتوافق مع نمط ARIA. على سبيل المثال، بدلاً من التنقل عبر عناصر القائمة، هل تعلم أنه يجب التنقل في شريط القوائم باستخدام مفاتيح الأسهم وإدارة التركيز الخاص به؟

على الرغم من أنني وجدت بعض البرامج التعليمية، إلا أنني في النهاية لم أتبعها بالكامل. أنا أكتب هذا لأنني أعتقد أن ما انتهيت من بنائه يستحق المشاركة - إذا كان لديك أيضًا ميل إلى المكونات الصغيرة والخطافات المخصصة.

على الرغم من أنني سأقوم ببناء هذه المدونة ببعض خطوات التطوير، إلا أن هدفي ليس كتابة دليل خطوة بخطوة. أثق في أنك تعرف أساسيات React وكيفية عمل الخطافات المخصصة.

أشارك فقط تفاصيل التنفيذ الرئيسية الآن، ولكني أخطط لتحديث هذه المقالة بمثال وضع الحماية للكود في المستقبل عندما يكون لدي المزيد من الوقت.

ماذا نبني؟

بالنسبة لهذه المدونة، فإننا نتجه نحو شريط قائمة التنقل، مثل تلك التي تراها في الجزء العلوي أو على جانب العديد من تطبيقات الويب. في شريط القائمة هذا، قد تحتوي بعض عناصر القائمة على قوائم فرعية، والتي سيتم فتحها/إغلاقها عند الإدخال/الخروج بالماوس.

ترميز HTML

أولاً وقبل كل شيء، يعد HTML الدلالي والأدوار المناسبة وسمات ARIA ضرورية لإمكانية الوصول. بالنسبة لنمط شريط القوائم، يمكنك قراءة المزيد من المستند الرسمي هنا.

إليك مثال لترميز HTML المناسب:

لاحظ أننا نستخدم علامة الزر لـ HTML الدلالي. يجب أن يحتوي الزر أيضًا على aria-haspopup لتنبيه قارئي الشاشة. وأخيرًا، يجب تعيين السمة المناسبة للأغنية الموسعة اعتمادًا على حالة القائمة.

عناصر

فلنتعرف على المكونات التي نحتاجها. من الواضح أننا بحاجة إلى مكون قائمة شامل، بالإضافة إلى مكون عنصر القائمة.

تحتوي بعض عناصر القائمة على قائمة فرعية والبعض الآخر لا يحتوي عليها. ستحتاج عناصر القائمة ذات القوائم الفرعية إلى إدارة حالاتها لفتح/إغلاق القائمة الفرعية عند التمرير وأحداث لوحة المفاتيح. لذلك يجب أن يكون مكونًا خاصًا به.

يجب أن تكون القوائم الفرعية مكونًا خاصًا بها أيضًا. على الرغم من أن القوائم الفرعية هي أيضًا مجرد حاويات لعناصر القائمة، إلا أنها لا تدير حالاتها أو تتعامل مع أحداث لوحة المفاتيح. وهذا ما يميزهم عن قائمة التنقل ذات المستوى الأعلى.

انتهى بي الأمر بكتابة هذه المكونات:

  • NavMenu للطبقة الخارجية من أشرطة القوائم.
  • MenuItem لعناصر القائمة الفردية.
    • رابط القائمة
    • MenuItemWithSubMenu
  • القائمة الفرعية للقائمة الفرعية الموسعة. يمكن دمج MenuItem بشكل متكرر داخل القائمة الفرعية.

إدارة التركيز

بكلمات واضحة جدًا، "إدارة التركيز" تعني فقط أن المكون يحتاج إلى معرفة الطفل الذي لديه التركيز. لذلك عندما يغادر تركيز المستخدم ويعود، سيتم إعادة تركيز الطفل الذي كان يركز عليه سابقًا.

من الأساليب الشائعة لإدارة التركيز "فهرس علامات التبويب المتجول"، حيث يكون للعنصر الذي تم التركيز عليه في المجموعة فهرس علامات تبويب بقيمة 0، بينما تحتوي العناصر الأخرى على فهرس علامات تبويب بقيمة -1. بهذه الطريقة، عندما يعود المستخدم إلى مجموعة التركيز، سيتم التركيز تلقائيًا على العنصر الذي يحتوي على فهرس علامة التبويب 0.

يمكن أن يبدو التنفيذ الأول لـ NavMenu كما يلي:

export function NavMenu ({ menuItems }) {
  // state for the currently focused index
  const [focusedIndex, setFocusedIndex] = useState(0);

  // functions to update focused index
  const goToStart = () => setCurrentIndex(0);
  const goToEnd = () => setCurrentIndex(menuItems.length - 1);
  const goToPrev = () => {
    const index = currentIndex === 0 ? menuItems.length - 1 : currentIndex - 1;
    setCurrentIndex(index);
  };
  const goToNext = () => {
    const index = currentIndex === menuItems.length - 1 ? 0 : currentIndex   1;
    setCurrentIndex(index);
  };

  // key down handler according to aria specification
  const handleKeyDown = (e) => {
    e.stopPropagation();
    switch (e.code) {
      case "ArrowLeft":
      case "ArrowUp":
        e.preventDefault();
        goToPrev();
        break;
      case "ArrowRight":
      case "ArrowDown": 
        e.preventDefault();
        goToNext();
        break;
      case "End":
        e.preventDefault();
        goToEnd();
        break;
      case "Home":
        e.preventDefault();
        goToStart();
        break;
      default:
        break;
    }
  }

  return (
    
  );
}

يوجد e.preventDefault() لمنع أشياء مثل ArrowDown من تمرير الصفحة.

إليك مكون MenuItem. دعونا نتجاهل العناصر ذات القائمة الفرعية لثانية واحدة فقط. نحن نستخدم useEffect وusePrevious وelement.focus() للتركيز على العنصر كلما تغير الفهرس المركز:

export function MenuItem ({ item, index, focusedIndex, setFocusedIndex }) {
  const linkRef = useRef(null);
  const prevFocusedIndex = usePrevious(focusedIndex);
  const isFocused = index === focusedIndex;

  useEffect(() => {
    if (linkRef.current 
      && prevFocusedIndex !== currentIndex 
      && isFocused) {
      linkRef.current.focus()
    }
  }, [isFocused, prevFocusedIndex, focusedIndex]);

  const handleFocus = () => {
    if (focusedIndex !== index) {
      setFocusedIndex(index);
    }
  };

  return (
    
  • {item.label}
  • ); }

    لاحظ أن العلامة هي التي يجب أن تحتوي على المرجع (زر عنصر القائمة مع القوائم الفرعية)، لذلك عندما يتم التركيز عليها، سيتم تشغيل سلوكيات لوحة المفاتيح الافتراضية كما هو متوقع، مثل التنقل على Enter. علاوة على ذلك، يتم تعيين فهرس علامة التبويب بشكل صحيح اعتمادًا على العنصر الذي تم التركيز عليه.

    نقوم بإضافة معالج حدث لحدث التركيز في حالة عدم كون حدث التركيز من حدث مفتاح/ماوس. إليك اقتباس من مستند الويب:

    لا تفترض أن جميع تغييرات التركيز ستأتي عبر أحداث المفاتيح والماوس: يمكن للتقنيات المساعدة مثل قارئات الشاشة ضبط التركيز على أي عنصر قابل للتركيز.

    قرص رقم 1

    إذا اتبعت useEffect الموضح أعلاه، فستجد أن العنصر الأول سيتم التركيز عليه حتى إذا لم يستخدم المستخدم لوحة المفاتيح للتنقل. لإصلاح ذلك، يمكننا التحقق من العنصر النشط واستدعاء focus() فقط عندما يبدأ المستخدم بعض أحداث لوحة المفاتيح، مما يحول التركيز بعيدًا عن النص.

      useEffect(() => {
        if (linkRef.current 
          && document.activeElement !== document.body // only call focus when user uses keyboard navigation
          && prevFocusedIndex !== focusedIndex
          && isCurrent) {
          linkRef.current.focus();
        }
      }, [isCurrent, focusedIndex, prevFocusedIndex]);
    

    إعادة استخدام المنطق والربط المخصص

    حتى الآن، لدينا مكونات NavMenu وMenuItemLink الوظيفية. دعنا ننتقل إلى عنصر القائمة مع القوائم الفرعية.

    بينما كنت أقوم ببنائه بسرعة، أدركت أن عنصر القائمة هذا سيشارك غالبية المنطق

    بيان الافراج تم إعادة نشر هذه المقالة على: https://dev.to/godsamit/building-an-accessible-navigation-menubar-with-react-hooks-blh?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] للحذف هو - هي
    أحدث البرنامج التعليمي أكثر>

    تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

    Copyright© 2022 湘ICP备2022001581号-3