أصبحت جداول البيانات جزءًا لا يتجزأ من الحوسبة الحديثة. إنها تتيح للمستخدمين تنظيم البيانات ومعالجتها وتحليلها في شكل جدولي. وقد وضعت تطبيقات مثل جوجل شيتس معيارًا لجداول البيانات التفاعلية والقوية.
في هذه المدونة، سنرشدك خلال عملية بناء تطبيق جدول بيانات باستخدام جافا سكريبت. سنركز على مفاهيم البرمجة الأساسية، ونستكشف ميزات جافا سكريبت، وسنقوم بتضمين مقاطع كود مفصلة مع شروحات.
الكود المصدر الكامل متاح هنا في كود بن.
ما هو جوجل شيت؟
جوجل شيت هو تطبيق قائم على الويب يسمح للمستخدمين بإنشاء وتحرير والتعاون في جداول البيانات عبر الإنترنت. يوفر ميزات مثل الصيغ، والتحقق من صحة البيانات، والمخططات، والتنسيق الشرطي.
مشروعنا يحاكي بعض الميزات الأساسية لجوجل شيت، مع التركيز على:
- الخلايا القابلة للتحرير.
- تحليل وتقييم الصيغ.
- التحديثات الحية من خلال نموذج النشر/الاشتراك.
- التنقل عبر لوحة المفاتيح واختيار الخلايا.
- تقييم الاعتماد الديناميكي بين الخلايا.
ميزات هذا المشروع
- الخلايا القابلة للتحرير: تتيح للمستخدمين إدخال نص أو معادلات في الخلايا.
- دعم الصيغ: يعالج الصيغ التي تبدأ بـ
=
ويقيم التعابير. - تحديثات مباشرة: تغييرات في الخلايا التابعة تؤدي إلى تحديثات باستخدام نموذج النشر/الاشتراك.
- تنقل عبر لوحة المفاتيح: يتيح الحركة بين الخلايا باستخدام مفاتيح الأسهم.
- تقييم ديناميكي: يضمن تحديثات في الوقت الحقيقي للصيغ التابعة لخلايا أخرى.
- معالجة الأخطاء: يوفر رسائل خطأ ذات معنى للإدخالات غير صحيحة أو التبعيات الدائرية.
- تصميم قابل للتوسع: يسمح بإضافة المزيد من الصفوف أو الأعمدة أو الميزات بسهولة.
المكونات الرئيسية للتطبيق
1. إدارة الوضع
const Mode = {
EDIT: 'edit',
DEFAULT: 'default'
};
يحدد هذا التعداد وضعين:
- تعديل: يتيح تعديل الخلية المحددة.
- افتراضي: يسمح بالتنقل والتفاعل دون تعديل.
لماذا استخدام الأوضاع؟
تبسط الأوضاع إدارة حالة واجهة المستخدم. على سبيل المثال، في وضع افتراضي، تؤدي إدخالات لوحة المفاتيح إلى الحركة بين الخلايا، بينما في وضع تعديل، تؤثر الإدخالات على محتوى الخلية.
2. فئة النشر/الاشتراك
يتولى نموذج النشر/الاشتراك إدارة الاشتراكات والتحديثات المباشرة. يمكن للخلايا الاشتراك في خلايا أخرى وتحديثها ديناميكيًا عند تغيير التبعيات.
class PubSub {
constructor() {
this.map = {};
}
get(source) {
let result = [];
let queue = [ (this.map[source] || [])];
while (queue.length) {
let next = queue.shift();
result.push(next.toUpperCase());
if (this.map[next]) queue.unshift(this.map[next]);
}
return result;
}
subscribeAll(sources, destination) {
sources.forEach((source) => {
this.map[source] = this.map[source] || [];
this.map[source].push(destination);
});
}
}
الميزات الرئيسية:
- إدارة التبعية الديناميكية: تتبع التبعيات بين الخلايا.
- انتشار التحديثات: يحدث الخلايا التابعة عند تغيير خلايا المصدر.
- بحث بالعرض أولاً: يتجنب الحلقات اللانهائية من خلال تتبع جميع العقد التابعة.
مثال على الاستخدام:
let ps = new PubSub();
ps.subscribeAll(['A1'], 'B1');
ps.subscribeAll(['B1'], 'C1');
console.log(ps.get('A1')); // Output: ['B1', 'C1']
3. إنشاء الصفوف والخلايا
class Cell {
constructor(cell, row, col) {
cell.id = `${String.fromCharCode(col + 65)}${row}`;
cell.setAttribute('data-eq', '');
cell.setAttribute('data-value', '');
if (row > 0 && col > -1) cell.classList.add('editable');
cell.textContent = col === -1 ? row : '';
}
}
class Row {
constructor(row, r) {
for (let c = -1; c < 13; c++) {
new Cell(row.insertCell(), r, c);
}
}
}
الميزات الرئيسية:
- توليد جدول ديناميكي: يسمح بإضافة الصفوف والأعمدة برمجيًا.
- تحديد الخلايا: ينشئ معرفات بناءً على الموقع (مثل A1، B2).
- خلايا قابلة للتعديل: يمكن تعديل الخلايا فقط إذا كانت صالحة (صفوف/أعمدة غير رأسية).
لماذا تستخدم الصفوف والخلايا الديناميكية؟
تتيح هذه الطريقة أن يكون حجم الجدول قابلًا للتوسع ومرنًا، داعمًا ميزات مثل إضافة الصفوف أو الأعمدة دون تغيير الهيكل.
4. معالجة الأحداث للتفاعل
addEventListeners() {
this.table.addEventListener('click', this.onCellClick.bind(this));
this.table.addEventListener('dblclick', this.onCellDoubleClick.bind(this));
window.addEventListener('keydown', this.onKeyDown.bind(this));
}
الميزات الرئيسية:
- حدث النقر: يحدد أو يعدل الخلايا.
- حدث النقر المزدوج: يمكّن من تعديل الصيغ.
- حدث الضغط على المفتاح: يدعم التنقل باستخدام مفاتيح الأسهم.
5. تحليل وتقييم الصيغ
function calcCell(expression) {
if (!expression) return 0;
return expression.split('+').reduce((sum, term) => {
let value = isNaN(term) ? getCellValue(term) : Number(term);
if (value === null) throw new Error(`Invalid cell: ${term}`);
return sum + Number(value);
}, 0);
}
الميزات الرئيسية:
- حساب ديناميكي: يحسب الصيغ التي تشير إلى خلايا أخرى.
- تقييم متكرر: يحل التبعيات المتداخلة.
- معالجة الأخطاء: يحدد المراجع غير الصالحة والتبعيات الدائرية.
6. معالجة الأخطاء لإدخال المستخدم
function isValidCell(str) {
let regex = /^[A-Z]{1}[0-9]+$/;
return regex.test(str);
}
الميزات الرئيسية:
- التحقق: يضمن أن المراجع المدخلة تتوافق مع معرفات خلايا صالحة.
- قابلية التوسع: يدعم توسيع الجدول الديناميكي دون كسر التحقق.
مواضيع JavaScript المغطاة
1. معالجة الأحداث
يدير التفاعلات مثل النقرات وضغط المفاتيح.
window.addEventListener('keydown', this.onKeyDown.bind(this));
2. معالجة DOM
ينشئ ويعدل عناصر DOM ديناميكياً.
let cell = document.createElement('td'); cell.appendChild(document.createTextNode('A1'));
3. الاستدعاء الذاتي
يعالج التبعيات ديناميكياً.
function calcCell(str) { if (isNaN(str)) { return calcCell(getCellValue(str)); } }
4. معالجة الأخطاء
يكشف عن الخلايا غير الصالحة والتبعيات الدائرية.
if (!isValidCell(p)) throw new Error(`invalid cell ${p}`);
الخاتمة
يظهر هذا المشروع جدول بيانات قوي باستخدام JavaScript. يستفيد من معالجة الأحداث، والاستدعاء الذاتي، وأنماط النشر/الاشتراك، مما يمهد الطريق لتطبيقات الويب المعقدة. قم بتوسيعه من خلال إضافة ميزات مثل تصدير البيانات، الرسوم البيانية، أو قواعد التنسيق.
المراجع
Source:
https://dzone.com/articles/spreadsheet-application-javascript-guide