आकस्मिक रूप से प्रकाशित! अधिक जानकारी के लिए कृपया बाद में वापस आएँ!
सुलभ वेब एप्लिकेशन बनाना सिर्फ एक अच्छा अभ्यास नहीं है - यह अब एक आवश्यकता है। हाल ही में, मुझे a11y पर फोकस के साथ एक नेविगेशन मेनूबार बनाने का अवसर मिला। जैसे-जैसे मैं शोध कर रहा था, मुझे एहसास हुआ कि वहां अधिकांश मेनूबार ARIA पैटर्न का अनुपालन नहीं करते हैं। उदाहरण के लिए, मेनू आइटमों को टैब करने के बजाय, क्या आप जानते हैं कि मेनूबार को तीर कुंजियों के साथ नेविगेट किया जाना चाहिए और अपना स्वयं का फोकस प्रबंधित करना चाहिए?
हालाँकि मुझे कुछ ट्यूटोरियल मिले, लेकिन अंततः मैंने उनका पूरी तरह से पालन नहीं किया। मैं यह इसलिए लिख रहा हूं क्योंकि मुझे लगता है कि मैंने जो बनाया वह साझा करने लायक है - यदि आपको भी छोटे घटकों और कस्टम हुक से लगाव है।
हालांकि मैं इस ब्लॉग को कुछ विकास चरणों के साथ तैयार करूंगा, मेरा लक्ष्य चरण-दर-चरण मार्गदर्शिका लिखना नहीं है। मुझे भरोसा है कि आप रिएक्ट की मूल बातें जानते होंगे और कस्टम हुक कैसे काम करते हैं।
मैं अभी केवल मुख्य कार्यान्वयन विवरण साझा कर रहा हूं, लेकिन भविष्य में जब मेरे पास अधिक समय होगा तो मैं इस लेख को कोड सैंडबॉक्स उदाहरण के साथ अपडेट करने की योजना बना रहा हूं।
इस ब्लॉग के लिए, हम एक नेव मेनू बार की ओर निर्माण कर रहे हैं, जैसा कि आप कई वेब एप्लिकेशन के शीर्ष पर या किनारे पर देखते हैं। इस मेनू बार में, कुछ मेनू आइटम में उप मेनू हो सकते हैं, जो माउस के एंटर/छोड़ने पर खुलेंगे/बंद होंगे।
सबसे पहले और सबसे महत्वपूर्ण, सिमेंटिक HTML और उपयुक्त भूमिकाएँ और ARIA विशेषताएँ पहुँच के लिए आवश्यक हैं। मेनूबार पैटर्न के लिए, आप यहां आधिकारिक दस्तावेज़ से अधिक पढ़ सकते हैं।
यहाँ उपयुक्त HTML मार्कअप के लिए एक उदाहरण दिया गया है:
ध्यान दें कि हम सिमेंटिक HTML के लिए बटन टैग का उपयोग कर रहे हैं। स्क्रीन पाठकों को सचेत करने के लिए बटन में aria-haspopup भी होना चाहिए। अंत में, मेनू स्थिति के आधार पर उपयुक्त एरिया-विस्तारित विशेषता निर्दिष्ट की जानी चाहिए।
आइए उन घटकों के बारे में जानें जिनकी हमें आवश्यकता है। जाहिर है, हमें एक समग्र मेनू घटक के साथ-साथ एक मेनू आइटम घटक की भी आवश्यकता है।
कुछ मेनू आइटम में एक उप मेनू होता है जबकि कुछ में नहीं। उप मेनू वाले मेनू आइटम को होवर और कीबोर्ड इवेंट पर उप मेनू के खुलने/बंद होने की स्थिति को प्रबंधित करने की आवश्यकता होगी। इसलिए इसका अपना घटक होना आवश्यक है।
उप मेनू का अपना घटक भी होना चाहिए। हालाँकि उप मेनू भी केवल मेनू आइटम के लिए कंटेनर हैं, वे अपने राज्यों का प्रबंधन नहीं करते हैं या कीबोर्ड ईवेंट को संभाल नहीं पाते हैं। यह उन्हें शीर्ष स्तरीय नेविगेशन मेनू से अलग करता है।
मैंने इन घटकों को लिखना समाप्त कर दिया:
बहुत स्पष्ट शब्दों में, "फोकस प्रबंधन" का मतलब केवल घटक को यह जानना है कि किस बच्चे का फोकस है। इसलिए जब उपयोगकर्ता का फोकस हटता है और वापस आता है, तो पहले से केंद्रित बच्चे को फिर से फोकस किया जाएगा।
फोकस प्रबंधन के लिए एक सामान्य तकनीक "रोविंग टैब इंडेक्स" है, जहां समूह में केंद्रित तत्व का टैब इंडेक्स 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() मौजूद है।
यहां मेनूआइटम घटक है। आइए बस एक सेकंड के लिए उप मेनू वाले आइटमों को अनदेखा करें। जब भी फोकस इंडेक्स बदलता है तो हम तत्व पर ध्यान केंद्रित करने के लिए यूज़इफेक्ट, यूज़प्रीवियस और एलिमेंट.फोकस() का उपयोग कर रहे हैं:
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 (
ध्यान दें कि यह एक ऐसा टैग है जिसमें रेफरी (सबमेनस के साथ मेनू आइटम के लिए बटन) होना चाहिए, इसलिए जब उन पर ध्यान केंद्रित किया जाता है, तो डिफ़ॉल्ट कीबोर्ड व्यवहार अपेक्षित रूप से शुरू हो जाएगा, जैसे कि एंटर पर नेविगेशन। इसके अलावा, फोकस किए गए तत्व के आधार पर टैब इंडेक्स को ठीक से असाइन किया जा रहा है।
यदि फोकस इवेंट कुंजी/माउस इवेंट से नहीं है तो हम फोकस इवेंट के लिए एक इवेंट हैंडलर जोड़ रहे हैं। यहां वेब डॉक से एक उद्धरण दिया गया है:
यह न मानें कि सभी फोकस परिवर्तन कुंजी और माउस घटनाओं के माध्यम से आएंगे: स्क्रीन रीडर जैसी सहायक प्रौद्योगिकियां फोकस को किसी भी फोकस करने योग्य तत्व पर सेट कर सकती हैं।
यदि आप ऊपर वर्णित उपयोग प्रभाव का पालन करते हैं, तो आप पाएंगे कि पहले तत्व पर फोकस होगा, भले ही उपयोगकर्ता ने नेविगेट करने के लिए कीबोर्ड का उपयोग नहीं किया हो। इसे ठीक करने के लिए, हम सक्रिय तत्व की जांच कर सकते हैं और केवल फोकस() को कॉल कर सकते हैं जब उपयोगकर्ता ने कुछ कीबोर्ड ईवेंट शुरू किया हो, जो फोकस को बॉडी से दूर स्थानांतरित कर देता है।
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 घटक हैं। चलिए उप मेनू वाले मेनू आइटम पर चलते हैं।
जैसा कि मैं इसे तेजी से बना रहा था, मुझे एहसास हुआ कि यह मेनू आइटम अधिकांश तर्क साझा करेगा
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3