نافذة ضمن النافذة لأي عنصر، وليس فقط <video>

François Beaufort
François Beaufort

Browser Support

  • Chrome: 116.
  • Edge: 116.
  • Firefox: 151.
  • Safari: not supported.

Source

تتيح واجهة برمجة التطبيقات "نافذة المستند ضمن النافذة" فتح نافذة تظهر دائمًا في المقدّمة ويمكن ملؤها بمحتوى HTML عشوائي، وهي توسّع واجهة برمجة التطبيقات الحالية "نافذة ضمن النافذة" لـ <video> التي تسمح فقط بوضع عنصر HTML <video> في نافذة "نافذة ضمن النافذة".

تشبه نافذة "نافذة ضمن النافذة" في Document Picture-in-Picture API نافذة فارغة من المصدر نفسه تم فتحها باستخدام window.open()، مع بعض الاختلافات:

  • تظهر نافذة "نافذة ضمن النافذة" فوق النوافذ الأخرى.
  • لا يمكن أن تستمر نافذة "نافذة ضمن النافذة" لفترة أطول من النافذة الأصلية.
  • لا يمكن التنقّل في نافذة "نافذة ضمن النافذة".
  • لا يمكن للموقع الإلكتروني ضبط موضع نافذة "نافذة ضمن النافذة".
نافذة &quot;نافذة ضمن النافذة&quot; تعرض فيديو الإعلان الترويجي لفيلم Sintel
نافذة "صورة داخل صورة" تم إنشاؤها باستخدام Document Picture-in-Picture API (العرض التوضيحي).

الحالة

الخطوة الحالة
1. إنشاء شرح مكتمل
2. إنشاء مسودة أولية للمواصفات قيد التقدم
3- جمع الملاحظات وتكرار التصميم قيد التقدم
4. مرحلة التجربة والتقييم مكتمل
5. تشغيل مكتمل (على الكمبيوتر)

حالات الاستخدام

يمكنك استخدام واجهة برمجة التطبيقات هذه بعدة طرق، بما في ذلك مشغّلات الفيديو المخصّصة واجتماعات الفيديو وتطبيقات الإنتاجية.

مشغّل فيديو مخصّص

يمكن لموقع إلكتروني توفير تجربة فيديو في وضع "نافذة ضمن النافذة" باستخدام واجهة برمجة التطبيقات الحالية لوضع "نافذة ضمن النافذة" في <video>، ولكنّها محدودة جدًا. تقبل نافذة "نافذة ضمن النافذة" الحالية عددًا قليلاً من المدخلات، كما أنّها محدودة القدرة على تصميمها. وباستخدام مستند كامل في وضع "نافذة ضمن النافذة"، يمكن للموقع الإلكتروني توفير عناصر تحكّم ومدخلات مخصّصة (مثل الترجمة والشرح وقوائم التشغيل وشريط التمرير السريع للإطار الزمني والإعجاب بالفيديوهات وعدم الإعجاب بها) لتحسين تجربة الفيديو في وضع "نافذة ضمن النافذة" للمستخدم.

اجتماعات الفيديو

يغادر المستخدمون غالبًا علامة تبويب المتصفّح مؤقتًا أثناء جلسة مؤتمرات الفيديو، مثلاً عند تقديم عرض من علامة تبويب أخرى إلى المكالمة أو تدوين الملاحظات أو تنفيذ أنشطة أخرى متعددة المهام. ومع ذلك، في معظم الحالات، يريد المستخدم مواصلة مشاهدة المكالمة، وبالتالي فإنّ هذه حالة استخدام مثالية لميزة "نافذة ضمن النافذة". مرة أخرى، إنّ التجربة الحالية التي يمكن أن يوفّرها موقع إلكتروني لمؤتمرات الفيديو باستخدام Picture-in-Picture API في <video> محدودة من حيث الأسلوب والإدخال. باستخدام مستند كامل في "نافذة ضمن النافذة"، يمكن للموقع الإلكتروني بسهولة دمج عدة بث فيديو في نافذة واحدة ضمن النافذة، بدون الاعتماد على اختراقات لوحة الرسم، وتوفير عناصر تحكّم مخصّصة، مثل إرسال رسالة أو كتم صوت مستخدم آخر أو رفع اليد.

الإنتاجية

أظهرت الأبحاث أنّ المستخدمين يحتاجون إلى المزيد من الطرق لزيادة إنتاجيتهم على الويب. تمنح ميزة "المستند في وضع نافذة ضمن النافذة" تطبيقات الويب المرونة اللازمة لإنجاز المزيد. سواء كان ذلك لتعديل النصوص أو تدوين الملاحظات أو قوائم المهام أو المراسلة والدردشة أو أدوات التصميم والتطوير، يمكن لتطبيقات الويب الآن إبقاء المحتوى متاحًا دائمًا.

واجهة

الخصائص

documentPictureInPicture.window
تعرض هذه السمة نافذة "نافذة ضمن النافذة" الحالية، إذا كانت متاحة. بخلاف ذلك، تعرض null.

الطُرق

documentPictureInPicture.requestWindow(options)

تعرض هذه الطريقة وعدًا يتم تنفيذه عند فتح نافذة "نافذة ضمن النافذة". يتم رفض الوعد إذا تم استدعاؤه بدون إيماءة من المستخدم. يحتوي قاموس options على العناصر الاختيارية التالية:

width
تضبط هذه السمة العرض الأولي لنافذة "نافذة ضمن النافذة".
height
تضبط هذه السمة الارتفاع الأولي لنافذة "نافذة ضمن النافذة".
disallowReturnToOpener
يخفي زر "الرجوع إلى علامة التبويب" في نافذة "النافذة ضمن النافذة" إذا كانت القيمة صحيحة. القيمة التلقائية هي "خطأ".
preferInitialWindowPlacement
فتح نافذة "نافذة ضمن النافذة" في موضعها وحجمها التلقائيَين إذا كانت القيمة صحيحة تكون القيمة التلقائية هي "خطأ".

الفعاليات

documentPictureInPicture.onenter
يتم تشغيلها في documentPictureInPicture عند فتح نافذة "نافذة ضمن النافذة".

أمثلة

يضبط رمز HTML التالي مشغّل فيديو مخصّصًا وعنصر زر لفتح مشغّل الفيديو في نافذة "النافذة ضمن النافذة".

<div id="playerContainer">
  <div id="player">
    <video id="video"></video>
  </div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>

فتح نافذة "نافذة ضمن النافذة"

تستدعي JavaScript التالية documentPictureInPicture.requestWindow() عندما ينقر المستخدم على الزر لفتح نافذة فارغة في وضع "نافذة ضمن النافذة". يتم حلّ الوعد الذي تم عرضه باستخدام كائن JavaScript لنافذة "نافذة ضمن النافذة". يتم نقل مشغّل الفيديو إلى تلك النافذة باستخدام append().

pipButton.addEventListener('click', async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

ضبط حجم نافذة "نافذة ضمن النافذة"

لضبط حجم نافذة "نافذة ضمن النافذة"، اضبط الخيارَين width وheight من documentPictureInPicture.requestWindow() على حجم نافذة "نافذة ضمن النافذة" المثالي. قد يقلّل Chrome من قيم الخيارات إذا كانت كبيرة جدًا أو صغيرة جدًا بحيث لا تتناسب مع حجم نافذة سهل الاستخدام.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window whose size is
  // the same as the player's.
  const pipWindow = await documentPictureInPicture.requestWindow({
    width: player.clientWidth,
    height: player.clientHeight,
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

إخفاء زر "الرجوع إلى علامة التبويب" في نافذة "نافذة ضمن النافذة"

لإخفاء الزر في نافذة "نافذة ضمن النافذة" الذي يتيح للمستخدم الرجوع إلى علامة التبويب الأصلية، اضبط الخيار disallowReturnToOpener الخاص بـ documentPictureInPicture.requestWindow() على true.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window which hides the "back to tab" button.
  const pipWindow = await documentPictureInPicture.requestWindow({
    disallowReturnToOpener: true,
  });
});

فتح وضع "نافذة ضمن النافذة" بالموضع والحجم التلقائيين

لعدم إعادة استخدام موضع أو حجم نافذة "النافذة ضمن النافذة" السابقة، اضبط الخيار preferInitialWindowPlacement الخاص بـ documentPictureInPicture.requestWindow() على true.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window in its default position / size.
  const pipWindow = await documentPictureInPicture.requestWindow({
    preferInitialWindowPlacement: true,
  });
});

نسخ أوراق الأنماط إلى PiP

لنسخ جميع أوراق أنماط CSS من النافذة الأصلية، يجب تكرار styleSheets المرتبط بشكل صريح أو المضمّن في المستند وإلحاقه بنافذة "نافذة ضمن النافذة". يُرجى العِلم أنّ هذه نسخة تُستخدم لمرة واحدة.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Copy style sheets over from the initial document
  // so that the player looks the same.
  [...document.styleSheets].forEach((styleSheet) => {
    try {
      const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join('');
      const style = document.createElement('style');

      style.textContent = cssRules;
      pipWindow.document.head.appendChild(style);
    } catch (e) {
      const link = document.createElement('link');

      link.rel = 'stylesheet';
      link.type = styleSheet.type;
      link.media = styleSheet.media;
      link.href = styleSheet.href;
      pipWindow.document.head.appendChild(link);
    }
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

التعامل مع إغلاق نافذة "نافذة ضمن النافذة"

استمِع إلى حدث "pagehide" في النافذة لمعرفة وقت إغلاق نافذة "نافذة ضمن النافذة" (إما لأنّ الموقع الإلكتروني بدأها أو لأنّ المستخدم أغلقها يدويًا). معالج الأحداث هو مكان مناسب لإعادة العناصر من نافذة "نافذة ضمن النافذة" كما هو موضّح هنا.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);

  // Move the player back when the Picture-in-Picture window closes.
  pipWindow.addEventListener("pagehide", (event) => {
    const playerContainer = document.querySelector("#playerContainer");
    const pipPlayer = event.target.querySelector("#player");
    playerContainer.append(pipPlayer);
  });
});

أغلِق النافذة الخاصة بميزة "نافذة ضمن النافذة" آليًا باستخدام الطريقة close().

// Close the Picture-in-Picture window programmatically.
// The "pagehide" event will fire normally.
pipWindow.close();

الاستماع إلى صوت عند انتقال الموقع الإلكتروني إلى وضع "نافذة ضمن النافذة"

استمِع إلى حدث "enter" على documentPictureInPicture لمعرفة وقت فتح نافذة "نافذة ضمن النافذة". يحتوي الحدث على عنصر window للوصول إلى نافذة ميزة "نافذة ضمن النافذة".

documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
});

الوصول إلى العناصر في نافذة "نافذة ضمن النافذة"

يمكنك الوصول إلى العناصر في نافذة "نافذة ضمن النافذة" من العنصر الذي تعرضه الدالة documentPictureInPicture.requestWindow()، أو باستخدام documentPictureInPicture.window.

const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
  // Mute video playing in the Picture-in-Picture window.
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
}

التعامل مع الأحداث من نافذة "نافذة ضمن النافذة"

يمكنك إنشاء أزرار وعناصر تحكّم والاستجابة لأحداث إدخال المستخدم (مثل "click")، كما هو الحال دائمًا في JavaScript.

// Add a "mute" button to the Picture-in-Picture window.
const pipMuteButton = pipWindow.document.createElement("button");
pipMuteButton.textContent = "Mute";
pipMuteButton.addEventListener("click", () => {
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
});
pipWindow.document.body.append(pipMuteButton);

تغيير حجم نافذة "نافذة ضمن النافذة"

استخدِم طريقتَي resizeBy() وresizeTo() لتغيير حجم نافذة نافذة ضمن النافذة، علمًا بأنّ كلتا الطريقتين تتطلّبان إجراءً تفاعليًا من المستخدم.

const resizeButton = pipWindow.document.createElement('button');
resizeButton.textContent = 'Resize';
resizeButton.addEventListener('click', () => {
  // Expand the Picture-in-Picture window's width by 20px and height by 30px.
  pipWindow.resizeBy(20, 30);
});
pipWindow.document.body.append(resizeButton);

التركيز على نافذة الفتح

استخدِم طريقة focus() Window للتركيز على نافذة الفتح من نافذة "نافذة ضمن النافذة". تتطلّب هذه الطريقة إجراءً تفاعليًا من المستخدم.

const returnToTabButton = pipWindow.document.createElement("button");
returnToTabButton.textContent = "Return to opener tab";
returnToTabButton.addEventListener("click", () => {
  window.focus();
});
pipWindow.document.body.append(returnToTabButton);

وضع العرض في CSS PiP

استخدِم وضع العرض picture-in-picture في CSS لكتابة قواعد CSS معيّنة لا يتم تطبيقها إلا عندما يتم عرض (جزء من) تطبيق الويب في وضع "نافذة ضمن النافذة".

@media all and (display-mode: picture-in-picture) {
  body {
    margin: 0;
  }
  h1 {
    font-size: 0.8em;
  }
}

رصد الميزات

للتحقّق مما إذا كانت واجهة برمجة التطبيقات Document Picture-in-Picture API متوافقة، استخدِم ما يلي:

if ('documentPictureInPicture' in window) {
  // The Document Picture-in-Picture API is supported.
}

العروض التوضيحية

  • مشغّل VideoJS: يمكنك التشغيل باستخدام Document Picture-in-Picture API عرض توضيحي لمشغّل VideoJS.
  • يستفيد تطبيق الويب Tomodoro، وهو تطبيق ويب يعتمد على تقنية بومودورو، من واجهة برمجة التطبيقات Document Picture-in-Picture API عندما تكون متاحة. اطّلِع على طلب السحب على GitHub.
‫Tomodoro، وهو تطبيق ويب يعتمد على تقنية البومودورو
نافذة "نافذة ضمن النافذة" في Tomodoro

مشاركة ملاحظاتك

الإبلاغ عن مشاكل في GitHub مع تقديم اقتراحات وطرح أسئلة