0Pricing
Frontend Academy · درس

Portals للنوافذ المنبثقة والتلميحات

استخدم ReactDOM.createPortal لعرض الأبناء داخل عقدة DOM مختلفة، مما يتيح إنشاء نوافذ منبثقة وتلميحات تتجاوز الحاويات التي تستخدم overflow:hidden

Portals للنوافذ المنبثقة والتلميحات درس مجاني في Frontend Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Frontend Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Frontend Academy 4 دروس في المجموع.

مشكلة الهروب من الحاوية

تحتاج النوافذ المنبثقة والتلميحات إلى التصيير في أعلى DOM، لتجاوز overflow:hidden وتراص z-index والسياقات المرتبطة بالتحويل التي يفرضها الأب. والحل هو البوابات.

واجهة createPortal البرمجية

تصيّر createPortal(children, container) ‏children داخل container (أي عقدة DOM)، مع إبقائهما منطقيًا أبناءً لمكوّن React من حيث الأحداث والسياق.

import { createPortal } from 'react-dom';

function Modal({ children, onClose }) {
  return createPortal(
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        {children}
      </div>
    </div>,
    document.body
  );
}

حاويات البوابات

الأهداف الشائعة: document.body، أو عنصر div مخصصًا باسم #modal-root في index.html، أو حاوية يُنشئها ref عند الطلب.

<!-- index.html -->
<div id="root"></div>
<div id="modal-root"></div>

// component:
const modalRoot = document.getElementById('modal-root');
return createPortal(<div>...</div>, modalRoot);

لماذا لا نُصيّرها مضمنة فحسب؟

إذا كان لدى أحد الآباء overflow: hidden، فستُقص النافذة المنبثقة الابنة. وإذا كان لدى أحد الآباء transform: scale، فسيصبح التموضع الثابت للنافذة المنبثقة نسبيًا إلى الأب. تتجنب البوابات كل ذلك.

تستمر الأحداث في الانتشار

رغم التصيير في موضع آخر من DOM، تنتشر أحداث React عبر شجرة المكوّنات، لا شجرة DOM. لذلك يستمر النقر داخل البوابة في الانتشار إلى معالجات onClick في مكوّنات React السلف.

الإغلاق عند النقر فوق الطبقة العلوية

أوقف انتشار الحدث في محتوى النافذة المنبثقة حتى لا تؤدي النقرات داخلها إلى إغلاقها.

function Modal({ onClose, children }) {
  return createPortal(
    <div className="backdrop" onClick={onClose}>
      <div className="content" onClick={e => e.stopPropagation()}>
        {children}
      </div>
    </div>,
    document.body
  );
}

الإغلاق عند الضغط على مفتاح Escape

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

useEffect(() => {
  const onKey = (e) => { if (e.key === 'Escape') onClose(); };
  window.addEventListener('keydown', onKey);
  return () => window.removeEventListener('keydown', onKey);
}, [onClose]);

إدارة التركيز في البوابات

عند فتح نافذة منبثقة: انقل التركيز إلى داخلها، وحاصر التركيز حتى إغلاقها، ثم أعد التركيز إلى العنصر الذي فتحها. استخدم مكتبة مثل focus-trap-react لتجنب إعادة تنفيذ ذلك.

عنصر dialog الأصلي

يتولى <dialog> في HTML أصليًا تموضع النافذة المنبثقة وخلفيتها وحصر التركيز وإغلاقها عند الضغط على Escape. وبالنسبة إلى معظم النوافذ المنبثقة، يُعد نقطة بداية أفضل من البوابة.

function Modal({ open, onClose, children }) {
  const ref = useRef(null);
  useEffect(() => {
    if (open) ref.current?.showModal();
    else ref.current?.close();
  }, [open]);
  return (
    <dialog ref={ref} onClose={onClose}>
      {children}
    </dialog>
  );
}

التلميحات والنوافذ العائمة

يُحدَّد موضع التلميحات بالنسبة إلى عنصر ارتكاز. وتتيح لها البوابة تجاوز سياقات التراص. ادمجها مع floating-ui لاكتشاف التصادمات وقلب الموضع وتحديده.

import { useFloating, autoUpdate } from '@floating-ui/react';

function Tooltip({ children, content }) {
  const { refs, floatingStyles } = useFloating({ whileElementsMounted: autoUpdate });
  const [open, setOpen] = useState(false);
  return (
    <>
      <button ref={refs.setReference} onMouseEnter={() => setOpen(true)} onMouseLeave={() => setOpen(false)}>
        {children}
      </button>
      {open && createPortal(
        <div ref={refs.setFloating} style={floatingStyles}>{content}</div>,
        document.body
      )}
    </>
  );
}

تنبيه متعلق بالتصيير من جانب الخادم

لا يوجد document على الخادم. إما أن تصيّر على العميل فقط (تحقق من typeof window)، أو استخدم dynamic في Next.js مع ssr:false.

إمكانية الوصول: aria-modal

ينبغي أن تحتوي حاويات النوافذ المنبثقة على role="dialog" وaria-modal="true" وaria-labelledby الذي يشير إلى عنوان النافذة المنبثقة. أو استخدم <dialog> الأصلي.

اختبار سريع

لماذا نستخدم createPortal للنوافذ المنبثقة بدلًا من تصييرها مضمنةً في شجرة المكوّنات؟

مراجعة: البوابات

يصيّر createPortal(children, container) عناصر DOM في موضع آخر، مع إبقاء شجرة React منطقية. ويحل مشكلات تجاوز overflow وtransform وz-index. وتستمر الأحداث في الانتشار عبر شجرة React. أضف الإغلاق عند الضغط على Escape وإدارة التركيز. ويتولى <dialog> الأصلي جزءًا كبيرًا من ذلك في النوافذ المنبثقة. ادمجه مع floating-ui للتلميحات. ولا تنسَ التصيير من جانب الخادم (تحقق من typeof window).

الأسئلة الشائعة

هل درس «Portals للنوافذ المنبثقة والتلميحات» مجاني؟

نعم — نص درس «Portals للنوافذ المنبثقة والتلميحات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Frontend Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Frontend Academy 4 دروس في المجموع.

ماذا ستتعلم في «Portals للنوافذ المنبثقة والتلميحات»؟

استخدم ReactDOM.createPortal لعرض الأبناء داخل عقدة DOM مختلفة، مما يتيح إنشاء نوافذ منبثقة وتلميحات تتجاوز الحاويات التي تستخدم overflow:hidden تتمرن على Frontend Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Frontend Academy؟

لا تُشترط خبرة سابقة. Frontend Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «Portals للنوافذ المنبثقة والتلميحات»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Frontend Academy هذا؟

نعم. كل درس في Frontend Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. المكوّنات المركّبة باستخدام Context
  2. أنماط Render Props وHOC
  3. Portals للنوافذ المنبثقة والتلميحات
  4. حدود الأخطاء
← العودة إلى Frontend Academy