مقدمة: لماذا تغيير URL دون إعادة تحميل هو قوة خارقة
\n\nتخيل: تفتح خدمة ويب حديثة - مثل عميل بريد إلكتروني أو محرر مستندات عبر الإنترنت. تتنقل بين المجلدات، تفتح الرسائل، تغير الإعدادات - والصفحة لا يتم إعادة تحميلها. وفي الوقت نفسه، يتغير شريط عنوان المتصفح، وتعمل أزرار "الرجوع" و"التقدم"، وتحفظ الإشارات المرجعية الحالة المطلوبة. كيف يعمل هذا؟ سحر تعديل URL دون إعادة تحميل الصفحة.
\n\nهذه ليست مجرد "ميزة" - إنها أساس التطبيقات أحادية الصفحة عالية الأداء (SPA). في الماضي، كان المطورون يستخدمون التجزئة (#)، لكنها كانت غير جميلة وغير مريحة. اليوم لدينا History API - أداة قوية تسمح بتغيير URL فوراً، بدون وميض، بدون فقدان الحالة، بدون طلبات HTTP إضافية.
\n\nفي هذه المقالة، سنشرح كيف يعمل pushState و replaceState، وكيف يؤثران على الأداء، وكيف لا تقع في الأخطاء أثناء التحسين. هيا بنا!
الأساسيات: History API وطرقه
\n\nمواصفات HTML5 أعطتنا واجهة window.history. الطريقتان الرئيسيتان لتغيير URL دون إعادة تحميل هما pushState و replaceState.
pushState - إضافة إدخال جديد في السجل
\n\npushState ينشئ إدخالاً جديداً في سجل المتصفح. يمكن للمستخدم الضغط على "الرجوع" والعودة إلى URL السابق.
// الصيغة\nhistory.pushState(state, title, url);\n\n// مثال\nhistory.pushState({ page: 1 }, 'الرئيسية', '/home');\n\n\nالمعلمات:
\n- \n
- state - كائن بيانات مرتبط بهذا الإدخال. يمكن تخزين أي بيانات قابلة للتسلسل (مثل حالة الفلتر، معرف العنصر). \n
- title - عنوان الصفحة (معظم المتصفحات تتجاهله، لكن من الأفضل تمرير سلسلة فارغة أو نص ذي معنى). \n
- url - URL الجديد. يجب أن يكون نسبياً أو مطلقاً، ولكن ضمن نفس الأصل (البروتوكول + النطاق + المنفذ). \n
replaceState - استبدال الإدخال الحالي
\n\nreplaceState يغير الإدخال الحالي في السجل دون إنشاء إدخال جديد. لن يتمكن المستخدم من العودة "للخلف" إلى URL السابق - سيتم استبداله.
// الصيغة\nhistory.replaceState(state, title, url);\n\n// مثال - تحديث URL عند تغيير الفلتر\nfunction applyFilter(filterName) {\n history.replaceState({ filter: filterName }, '', `?filter=${filterName}`);\n updateUI(filterName);\n}\n\n\npopstate - الاستماع لتغييرات السجل
\n\nعندما يضغط المستخدم على "الرجوع" أو "التقدم"، يقوم المتصفح بتوليد حدث popstate. مهم: pushState و replaceState لا يستدعيان هذا الحدث - يجب معالجته بشكل منفصل.
window.addEventListener('popstate', function(event) {\n if (event.state) {\n // استعادة الحالة بناءً على البيانات من event.state\n restorePageState(event.state);\n } else {\n // إذا كانت الحالة فارغة - ربما خرج المستخدم خارج نطاق تطبيقنا\n loadDefaultState();\n }\n});\n\n\nتحسين الأداء: ما هو مهم معرفته
\n\nتعديل URL سريع. لكن هناك تفاصيل قد تحول القوة الخارقة إلى مصدر للأخطاء.
\n\n1. لا تستدعي pushState بشكل متكرر
\n\nكل استدعاء لـ pushState يضيف إدخالاً في السجل. إذا كنت تستدعيه مع كل حركة ماوس أو كل حرف في البحث - سينتفخ السجل، وسيضطر المستخدم للضغط على "الرجوع" 100 مرة للخروج من الفلتر. استخدم replaceState للحالات الوسيطة، و pushState للإجراءات المكتملة منطقياً (مثل فتح صفحة جديدة).