تطبيقات الويب التقدمية
الدعم غير المتصل
الدعم غير المتصل في تطبيقات الويب التقدمية
واحدة من أقوى ميزات تطبيقات الويب التقدمية هي القدرة على العمل دون اتصال بالإنترنت. من خلال تطبيق الدعم المناسب للوضع غير المتصل، يمكن لتطبيقك توفير تجربة سلسة حتى عندما يفقد المستخدم الاتصال بالشبكة.
اكتشاف الحالة غير المتصلة
توفر JavaScript خاصية navigator.onLine للتحقق من حالة الاتصال بالشبكة:
<script>
// التحقق من الحالة الحالية للاتصال
if (navigator.onLine) {
console.log('متصل بالإنترنت');
} else {
console.log('لا يوجد اتصال بالإنترنت');
}
// الاستماع لأحداث الاتصال/عدم الاتصال
window.addEventListener('online', () => {
console.log('تم استعادة الاتصال');
updateUIForOnlineMode();
});
window.addEventListener('offline', () => {
console.log('فقد الاتصال');
updateUIForOfflineMode();
});
function updateUIForOnlineMode() {
document.body.classList.remove('offline-mode');
document.body.classList.add('online-mode');
showNotification('عدت للاتصال بالإنترنت!', 'success');
}
function updateUIForOfflineMode() {
document.body.classList.remove('online-mode');
document.body.classList.add('offline-mode');
showNotification('أنت غير متصل. قد تكون بعض الميزات محدودة.', 'warning');
}
</script>
تحذير: خاصية
navigator.onLine ليست موثوقة بنسبة 100٪. إنها تكتشف فقط ما إذا كان هناك اتصال بالشبكة، وليس ما إذا كان الإنترنت متاحًا فعليًا. قد يكون الجهاز متصلاً بشبكة WiFi بدون إنترنت، وستظل navigator.onLine تُرجع true.
إنشاء صفحة للوضع غير المتصل
نمط شائع هو حفظ صفحة مخصصة للوضع غير المتصل يتم عرضها عندما يحاول المستخدم التنقل أثناء عدم الاتصال:
// في عامل الخدمة (sw.js)
const OFFLINE_PAGE = '/offline.html';
const CACHE_NAME = 'offline-v1';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
OFFLINE_PAGE,
'/styles/offline.css',
'/images/offline-icon.svg'
]);
})
);
self.skipWaiting();
});
self.addEventListener('fetch', (event) => {
// معالجة طلبات التنقل فقط (صفحات HTML)
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => {
return caches.match(OFFLINE_PAGE);
})
);
}
});
مثال على صفحة HTML للوضع غير المتصل
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>أنت غير متصل</title>
<link rel="stylesheet" href="/styles/offline.css">
</head>
<body>
<div class="offline-container">
<img src="/images/offline-icon.svg" alt="غير متصل">
<h1>أنت غير متصل</h1>
<p>يبدو أنك فقدت الاتصال بالإنترنت.</p>
<p>لا تقلق، لا يزال بإمكانك الوصول إلى المحتوى الذي شاهدته سابقًا.</p>
<button onclick="window.history.back()">العودة</button>
<button onclick="location.reload()">حاول مرة أخرى</button>
</div>
</body>
</html>
استراتيجيات التدهور الرشيق
عند تطبيق الدعم غير المتصل، ضع في اعتبارك أنماط تجربة المستخدم التالية:
أفضل الممارسات لتجربة المستخدم غير المتصل:
- المؤشرات البصرية: إظهار شريط أو رمز عند عدم الاتصال
- تعطيل الميزات: إظهار الميزات التي تتطلب الاتصال بشكل باهت أو إخفاؤها
- إجراءات الصف: حفظ إجراءات المستخدم محليًا ومزامنتها عند الاتصال
- المحتوى المخزن: إظهار المحتوى المحمل مسبقًا مع الطوابع الزمنية
- رسائل مفيدة: شرح ما يعمل وما لا يعمل دون اتصال
تخزين البيانات دون اتصال
قم بتخزين البيانات محليًا للوصول دون اتصال باستخدام آليات التخزين المختلفة:
// استخدام localStorage للبيانات البسيطة
function saveOfflineData(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
console.log('تم حفظ البيانات للاستخدام دون اتصال');
} catch (e) {
console.error('فشل حفظ البيانات دون اتصال:', e);
}
}
function getOfflineData(key) {
try {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch (e) {
console.error('فشل استرجاع البيانات دون اتصال:', e);
return null;
}
}
// التحقق من حالة الاتصال قبل الجلب
async function fetchWithOfflineFallback(url, storageKey) {
if (navigator.onLine) {
try {
const response = await fetch(url);
const data = await response.json();
saveOfflineData(storageKey, data);
return data;
} catch (error) {
console.warn('فشل الجلب، استخدام البيانات المخزنة');
return getOfflineData(storageKey);
}
} else {
return getOfflineData(storageKey);
}
}
الكشف المتقدم عن عدم الاتصال
للحصول على كشف أكثر موثوقية عن عدم الاتصال، قم بتنفيذ فحص نبض القلب:
class ConnectionMonitor {
constructor(checkInterval = 30000) {
this.checkInterval = checkInterval;
this.isOnline = navigator.onLine;
this.listeners = [];
this.init();
}
init() {
// الاستماع لأحداث المتصفح
window.addEventListener('online', () => this.updateStatus(true));
window.addEventListener('offline', () => this.updateStatus(false));
// فحص نبض القلب الدوري
setInterval(() => this.checkConnection(), this.checkInterval);
}
async checkConnection() {
try {
const response = await fetch('/ping', {
method: 'HEAD',
cache: 'no-cache'
});
this.updateStatus(response.ok);
} catch (error) {
this.updateStatus(false);
}
}
updateStatus(isOnline) {
if (this.isOnline !== isOnline) {
this.isOnline = isOnline;
this.listeners.forEach(callback => callback(isOnline));
}
}
onChange(callback) {
this.listeners.push(callback);
}
}
// الاستخدام
const monitor = new ConnectionMonitor();
monitor.onChange((isOnline) => {
console.log(isOnline ? 'متصل' : 'غير متصل');
updateUI(isOnline);
});
ملاحظة: يضيف فحص نبض القلب عبئًا على الشبكة. استخدم فترة زمنية معقولة (30-60 ثانية) لتحقيق التوازن بين الاستجابة واستخدام الموارد.
بنية غير متصلة أولاً
في النهج غير المتصل أولاً، يحاول التطبيق دائمًا التحميل من التخزين المؤقت أولاً، ثم يتم التحديث من الشبكة:
// عامل الخدمة: استراتيجية التخزين المؤقت أولاً
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
// إرجاع النسخة المخزنة إذا كانت متوفرة
if (cachedResponse) {
// تحديث التخزين المؤقت في الخلفية
fetch(event.request).then((networkResponse) => {
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, networkResponse);
});
});
return cachedResponse;
}
// وإلا جلب من الشبكة
return fetch(event.request).then((networkResponse) => {
// حفظ الاستجابة الجديدة
return caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
});
})
);
});
تمرين:
- أنشئ صفحة offline.html مع تنسيق مخصص
- حدث عامل الخدمة الخاص بك لحفظ وعرض صفحة الوضع غير المتصل
- أضف مؤشرات بصرية في تطبيقك لإظهار حالة الاتصال/عدم الاتصال
- نفذ احتياطي localStorage لبيانات API
- اختبر بتعطيل اتصال الشبكة الخاص بك