كيفية عرض تنبيه "التغييرات غير محفوظة" في تطبيقات الويب لمنع فقدان البيانات

كتب بواسطة idriss douiri profile picture إدريس الدويري

حدث بتاريخ

3 min read

مربع حوار تأكيد في المتصفح عند المغادرة مع وجود تغييرات غير محفوظة
مشاركة

تخيّل أنك تكتب بعض الملاحظات في موقع لتدوين الملاحظات، وبعد انتهائك تغلق التبويب معتقدًا أن التغييرات تم حفظها تلقائيًا، لكنك تتفاجأ لاحقًا أن شيئًا لم يُحفظ.

هذه تجربة سيئة للمستخدم. ولكان من الأفضل لو عرض الموقع تنبيهًا ليذكزك أن تغييراتك لم تُحفظ بعد، مما يمنع فقدان البيانات.

لحسن الحظ، يوفّر لنا حدث beforeunload في JavaScript طريقة سهلة لتنفيذ هذه الميزة. وينبغي على كل موقع يدعم هذا السيناريو أن يطبّقها.

ما هو حدث beforeunload؟

حدث beforeunload هو حدث في المتصفح يتم إطلاقه عندما تكون الصفحة على وشك الإغلاق، ويمكن تفعيله في الحالات التالية:

  • إعادة تحميل الصفحة
  • إغلاق التبويب
  • الانتقال إلى مستند آخر (سواء بالضغط على زر الرجوع أو العودة)

دعم المتصفحات:

  • chrome: supported
  • edge: supported
  • firefox: supported
  • safari: supported

كيف نعرض رسالة التأكيد الأصلية للمتصفح؟

الطريقة الحديثة هي الاستماع لحدث beforeunload ثم استخدام preventDefault() على كائن الحدث.

وبالنسبة للمتصفحات القديمة، نستخدم event.returnValue ونعيّنه إلى سلسلة فارغة.

window.addEventListener("beforeunload", (event) => {
  event.preventDefault(); // مطلوب للمتصفحات الحديثة
  event.returnValue = ""; // مطلوب للمتصفحات القديمة
});

أفضل الممارسات لاستخدام beforeunload

لأسباب تتعلق بالأداء، من الأفضل الاستماع لهذا الحدث فقط عندما تكون هناك تغييرات غير محفوظة، وإزالة المستمع عندما لا تكون هناك بيانات مهددة بالفقدان.

إليكم مثالًا مأخوذا من MDN يوضّح ذلك:

<form>
  <input type="text" name="name" id="name" />
</form>

<script>
const beforeUnloadHandler = (event) => {
  event.preventDefault(); // موصى به
  event.returnValue = true; // لدعم المتصفحات القديمة مثل Chrome/Edge < 119
};

const nameInput = document.querySelector("#name");

nameInput.addEventListener("input", (event) => {
  if (event.target.value !== "") {
    window.addEventListener("beforeunload", beforeUnloadHandler);
  } else {
    window.removeEventListener("beforeunload", beforeUnloadHandler);
  }
});
</script>

في هذا المثال، نستمع لحدث beforeunload فقط عند إدخال المستخدم لنص، ونزيل المستمع عند تفريغ الحقل لتحسين الكفاءة.

هل يمكن تخصيص رسالة التأكيد؟

لأسباب أمنية، تعرض المتصفحات رسالة عامة لا يمكن تعديلها. على سبيل المثال، في متصفح Chrome تظهر رسالة: “Changes you made may not be saved.” والتي تعني “التغييرات التي قمت بها ربما لم تحفظ”.

لقطة شاشة لتنبيه تأكيد يظهر عند مغادرة موقع CodePen مع وجود تغييرات غير محفوظة.
تنبيه تأكيد يظهر عند مغادرة CodePen مع وجود تغييرات غير محفوظة في Chrome.

مشاكل في تطبيقات الصفحة الواحدة (SPAs):

لا يُفعَّل الحدث beforeunload إلا عندما يقوم المتصفح فعليًا بإلغاء تحميل الصفحة (أي عند الانتقال الكامل إلى صفحة أخرى). أما في تطبيقات الصفحة الواحدة (SPAs) مثل React أو Vue أو Angular، فإن معظم عمليات التنقل تتم داخل التطبيق نفسه عبر موجّه من جهة العميل (Client-side router)، مما يعني أن الصفحة لا تُغلق أبدًا، وبالتالي لن يُفعَّل الحدث beforeunload على الإطلاق. فإذا نقر المستخدم على رابط للانتقال من النموذج الذي يملؤه إلى مسار آخر داخل التطبيق، فلن يظهر له أي تحذير.

الحل هنا لا يكمن في API المتصفح (Browser API)، بل في ميزة حظر التنقل المدمجة في الموجّه (Router) الذي تستخدمه. يمتلك كل إطار عمل (Framework) رئيسي طريقته الخاصة للتعامل مع هذه الحالة؛ لذا ابحث عن ميزة “حراس التنقل” (Navigation guards) أو “أدوات الحظر” (Blockers) الخاصة بالإطار الذي تعمل عليه.

بالنسبة لـ React تحديدًا، إذا كنت تستخدم React Router بإصدار 6.4 فما أحدث، فإن الـ Hook الذي تحتاجه هو useBlocker. حيث يتيح لك اعتراض عمليات التنقل داخل التطبيق، وإظهار رسالة تأكيد للمستخدم قبل تغيير المسار.

مشاكل استخدام beforeunload

رغم أن الحدث يعمل جيدًا على متصفحات الحواسيب، إلا أنه قد لا يعمل كما هو متوقع على الهواتف. فتطبيقات الهاتف قد تدخل في وضع الخلفية ويتم إغلاقها لأي سبب.

والبديل الفعّال في هذه الحالة هو استخدام حدث visibilitychange. هناك مقال رائع من Ilya Grigorik بعنوان “لا تفقد حالة المستخدم والتطبيق - استخدم رؤية الصفحة”.

Share this post