Frontend Development

إتقان جداول البيانات التفاعلية المتاحة للجميع باستخدام جافاسكريبت الخام وARIA

تُعد جداول البيانات من أكثر العناصر دلالية وقوة في HTML، لكنها غالباً ما تُساء استخدامها أو تُزال منها ميزات إمكانية الوصول عندما يحاول المطورون تعزيزها بالتفاعلية. بالنسبة لمطوري الواجهات الأمامية من المستوى المتوسط إلى المتقدم، تكمن التحدي ليس فقط في جعل الجدول يبدو جيداً، بل في ضمان أن التفاعلات المعقدة—مثل الفرز، والتصفية، والتصفح—يمكن إدراكها وتشغيلها من قبل الجميع، بما في ذلك المستخدمين الذين يعتمدون على تقنيات المساعدة. يستكشف هذا الدليل كيفية تنفيذ جداول بيانات تفاعلية قوية باستخدام جافاسكريبت الخام (Vanilla JavaScript)، والاستفادة من معايير WAI-ARIA (مبادرة إمكانية الوصول على الويب – تطبيقات الإنترنت الغنية المتاحة) لسد الفجوة بين HTML الثابت وواجهات المستخدم الديناميكية.

الأساس: HTML الدلالي أمر لا غنى عنه

قبل كتابة سطر واحد من جافاسكريبت، يجب أن يكون هيكل HTML سليماً. تعتمد قارئات الشاشة على المعالم الدلالية لفهم سياق البيانات. يجب أن يتضمن جدول البيانات الأساسي دائماً ``، و``، و``، و`` (حيثما ينطبق ذلك). يُعد `` حاسماً لأنه يقدم ملخصاً لمحتوى الجدول، والذي تعلنه قارئات الشاشة فوراً عند دخول منطقة الجدول. علاوة على ذلك، استخدم دائماً عناصر `` مع سمات `scope` المناسبة. يربط تعيين `scope="col"` أو `scope="row"` خلايا الرأس بشكل صريح بخلايا البيانات المقابلة لها، مما يلغي الغموض للمستخدمين الذين يتنقلون عبر لوحة المفاتيح أو الأوامر الصوتية.

إضافة التفاعلية باستخدام جافاسكريبت الخام

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

إدارة حالة الفرز باستخدام ARIA

عندما ينقر المستخدم على رأس عمود للفرز، يجب تحديث سمة `aria-sort` على ذلك الرأس. يمكن أن تأخذ هذه السمة قيم `ascending` (تصاعدي)، و`descending` (تنازلي)، و`none` (لا يوجد)، أو `other` (آخر). يسمح هذا لقارئات الشاشة بالإعلان، "اسم العمود، مرتب تنازلياً"، مما يوفر تغذية راجعة حاسمة للمستخدم. إليك مثال عملي لكيفية التعامل مع حدث النقر لتبديل ترتيب الفرز باستخدام ARIA:
const headers = document.querySelectorAll('table th[data-sortable]');

headers.forEach(header => {
  header.addEventListener('click', () => {
    const direction = header.getAttribute('aria-sort') === 'ascending' ? 'descending' : 'ascending';
    
    // إزالة حالة 'sorted' من الرؤوس الأخرى
    headers.forEach(h => h.setAttribute('aria-sort', 'none'));
    
    // تعيين الحالة الجديدة
    header.setAttribute('aria-sort', direction);
    
    // تشغيل منطق الفرز هنا
    sortTable(header, direction);
  });
});

التعامل مع تغييرات المحتوى الديناميكي

أحد أكثر الأخطاء شيوعاً في جافاسكريبت المتاح هو فشل الإعلان عن التغييرات لمستخدمي قارئات الشاشة. إذا قمت بتصفية جدول أو التصفح إلى الصفحة التالية، يتغير DOM، لكن مستخدم قارئ الشاشة قد لا يدرك أن المحتوى قد تم تحديثه. لحل هذه المشكلة، استخدم منطقة `aria-live`. أنشئ عنصراً منفصلاً، غالباً ما يكون مخفياً بصرياً، يعمل كمنطقة حية. عندما تقوم جافاسكريبت بتحديث محتوى الجدول، قم أيضاً بتحديث هذه المنطقة برسالة موجزة.
<div id="table-status" aria-live="polite" class="sr-only"></div>

<script>
function updateTableContent(filteredRows) {
  // 1. تحديث tbody
  tbody.innerHTML = '';
  filteredRows.forEach(row => tbody.appendChild(row));

  // 2. الإعلان عن التغيير لقارئات الشاشة
  const statusRegion = document.getElementById('table-status');
  statusRegion.textContent = `تم تحديث الجدول. عرض ${filteredRows.length} نتيجة.`;
  
  // مسح الرسالة بعد تأخير لمنع الازدحام
  setTimeout(() => { statusRegion.textContent = ''; }, 1000);
}
</script>
تضمن السمة `aria-live="polite"` أن يحدث الإعلان بعد أن ينهي المستخدم مهمته الحالية، مما يتجنب المقاطعات، بينما `aria-live="assertive"` سيقاطع فوراً (استخدمه بحذر).

التصفح والتصفح عبر الصفحات

عند تنفيذ التصفح عبر الصفحات، تأكد من أن كل رابط صفحة مُسمى بوضوح. تجنب استخدام نصوص عامة مثل "التالي" أو "1" دون سياق. بدلاً من ذلك، استخدم `aria-label` لوصف الإجراء، مثل `aria-label="الذهاب إلى الصفحة 2"` أو `aria-label="الذهاب إلى الصفحة التالية"`. هذا يوفر سياقاً تفتقر إليه الروابط العامة. علاوة على ذلك، قم بتجميع عناصر التحكم في التصفح عبر الصفحات باستخدام عنصر `
Share: