تحسين UX باستخدام مفتاح Tab

عند تطوير التطبيقات ، نادراً ما ينتبه البائعون الأماميون لكيفية استخدام المستخدم لوظائف لوحة المفاتيح التي يوفرها المستعرض. لست استثناءً ، لكن في أحد الأيام حصلت على مهمة تتعلق بـ UX والتحولات بالضغط على "Tab" و "Shift + Tab".

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

صورة

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

صورة

كما ترون ، فإن السلوك "الأصلي" لا يلبي المتطلبات. لذلك ، دعونا نحل هذه المشكلة. الحل ليس معقدًا ، لذا فكر في الأمر.

سيكون مثالياً إذا كانت هناك بعض "البوابات" التي تمنع "القفز" من التركيز من آخر (مع "علامة تبويب") أو العنصر الأول (مع "Shift + Tab") مع "tabindex" أو دعم التركيز بشكل افتراضي. لذلك ، الجوهر بسيط: "البوابات" الخاصة بنا هي "عناصر إدخال" مخفية ، والتي تتلقى حدث "حدث" كوسيطة أثناء حدث "onFocus" وتعيد التركيز إلى العنصر الذي جاءت منه. التوضيح أدناه.

صورة

الحصول على العنصر السابق ممكن باستخدام خاصية "relatedTarget" لكائن "الحدث". تصور للحل أدناه.

صورة

وهنا هو الكود نفسه. تجدر الإشارة إلى أنه لا يوجد بناء جملة "ES6 +" ، لأن الفكرة هي دعم الكود مع متصفحات مختلفة دون توصيل "transpilers" مختلفة مثل Babel.

function getGateInput(handleTabOut) { var input = document.createElement("input"); // not visibiliy:hidden or display:none as need to focus on this element var hiddingStyle = "opacity: 0;cursor: none;position: absolute;top: -10px;left: -10px;"; input.setAttribute("style", hiddingStyle); input.addEventListener("focus", handleTabOut); return input; } 

لا يوجد شيء معقد: يتم إنشاء "إدخال" ، يتم تعيين أنماط "تخفي" "بواباتنا". هنا ، لا يتم استخدام كلمة "display: none" لأن المتصفح لا يركز "Tabs" على هذه العناصر. بسبب هذا السلوك ، يلزم جعل العنصر شفافًا ونقله خارج إطار المستعرض.

 function getTabOutHandler(element, GATES) { return function(event) { var relatedTarget = event.relatedTarget || event.fromElement; var target = event.target; var gatesTrapped = target === GATES[0] || target === GATES[1]; if (gatesTrapped && isChild(relatedTarget, element)) { event.preventDefault(); relatedTarget.focus(); } }; } 

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

من أجل التركيز في الحاوية ، نحتاج إلى فتح وإغلاق "البوابة". سنفعل ذلك من خلال تعيين سمة "tabindex" . (-1 - لا تركز مع علامات التبويب ، 0 - التركيز وفقا للتيار)

 function moveGates(open, GATES) { GATES[0].setAttribute("tabindex", open ? -1 : 0); GATES[1].setAttribute("tabindex", open ? -1 : 0); } 

للتحكم في البوابات ، سنقوم بإعداد معالج "يستمع" إلى الضغط على Tab (الكود 9) وإذا كان العنصر المركّز (activeElement) داخل الحاوية ، ثم أغلق "البوابة" ، وإلا افتحه.

 window.addEventListener("keydown", function(event) { if (event.keyCode === 9) { if (isChild(document.activeElement, element)) { moveGates(false, GATES); } else { moveGates(true, GATES); } } }); 

في المجموع


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

Source: https://habr.com/ru/post/ar469749/


All Articles