Spec-Zone.ru › Web APIs

Использование API управления окнами

Это руководство объясняет, как использовать API управления окнами. Приведенный ниже пример кода взят из нашего примера Многооконной обучающей среды (см. исходный код).

Обнаружение возможности

Вы можете обнаружить API управления окнами, проверив существование getScreenDetails в текущем window экземпляре. Например, вы можете предоставить кнопку для открытия многооконного отображения, если API поддерживается, или другое взаимодействие, например, создание ссылок на разные страницы, если оно не поддерживается:

if ("getScreenDetails" in window) {
  // The Window Management API is supported
  createButton();
} else {
  // The Window Management API is not supported
  createLinks(sites);
}

Базовое использование

Сердцем API управления окнами является метод Window.getScreenDetails(), который возвращает объект, содержащий подробности всех доступных пользователю экранов:

const screenDetails = await window.getScreenDetails();

// Return the number of screens
const noOfScreens = screenDetails.screens.length;

При вызове getScreenDetails(), пользователю будет предложено разрешить управление окнами на всех его дисплеях (статус этого разрешения можно проверить с помощью Permissions.query() для запроса window-management). Если пользователь предоставит разрешение, будет возвращен объект ScreenDetails. Этот объект содержит следующие свойства:

  • screens: Массив объектов ScreenDetailed, каждый из которых содержит подробную информацию о отдельном экране, доступном в системе (см. ниже). Этот массив также полезен для определения количества доступных экранов с помощью screens.length.
  • currentScreen: Единственный объект ScreenDetailed, содержащий подробную информацию о экране, на котором отображается текущее окно браузера.

Объекты ScreenDetailed наследуют свойства интерфейса Screen и содержат полезную информацию для размещения окон на определенных экранах.

Примечание: Вы можете ограничить функциональность в зависимости от того, есть ли у пользователя более одного доступного экрана, используя свойство Window.screen.isExtended. Оно возвращает true если устройство имеет несколько экранов, и false если нет.

Открытие окон

Вам все равно потребуется использовать Window.open() для открытия и управления окнами, но вышеприведенное предоставляет вам более подробную информацию для этого в многоэкранной среде. Например, утилитарная функция может выглядеть так:

// Array to hold references to the currently open windows
let windowRefs = [];

// ...

function openWindow(left, top, width, height, url) {
  const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`;
  const windowRef = window.open(
    url,
    "_blank", // needed for it to open in a new window
    windowFeatures,
  );

  if (windowRef === null) {
    // If the browser is blocking new windows, close any windows that were
    // able to open and display instructions to help the user fix this problem
    closeAllWindows();
    popoverElem.showPopover();
  } else {
    // Store a reference to the window in the windowRefs array
    windowRefs.push(windowRef);
  }
}

Затем вы вызовите эту функцию и откроете окна на определенных экранах так:

const screen1 = screenDetails.screens[0];
const screen2 = screenDetails.screens[1];
// Windows will be a third the width and the full height of the screen
// The available width of screen1, minus 3 times the horizontal browser chrome
// width, divided by 3
const windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3);
// The available height of screen1, minus the vertical browser chrome width
const windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y);

// Open a window a third of the width and the entire height of the primary screen
openWindow(
  screen1.availLeft,
  screen1.availTop,
  windowWidth,
  windowHeight,
  sites[1].url,
);

// ...

Закрытие всех окон

После открытия каждого окна мы добавляем ссылку в массив windowRefs. Это позволяет, например, закрывать все окна при закрытии одного:

function closeAllWindows() {
  // Loop through all window refs and close each one
  windowRefs.forEach((windowRef) => {
    windowRef.close();
  });
  windowRefs = [];
}

// Check whether one of our popup windows has been closed
// If so, close them all

closeMonitor = setInterval(checkWindowClose, 250);

function checkWindowClose() {
  if (windowRefs.some((windowRef) => windowRef.closed)) {
    closeAllWindows();
    clearInterval(closeMonitor);
  }
}

Примечание: В наших экспериментах метод опроса setInterval(), показанный выше, показал наилучшие результаты для обнаружения закрытия окна в случае нескольких окон. Использование таких событий, как beforeunload, pagehide или visibilitychange, оказалось ненадежным, потому что при одновременном открытии нескольких окон быстрая смена фокуса/видимости, похоже, преждевременно вызывала обработчик функций.

Примечание: Один из недостатков приведенного выше примера заключается в том, что он использует постоянные значения для представления размеров частей пользовательского интерфейса Chrome в вычислениях — WINDOW_CHROME_X и WINDOW_CHROME_Y — для получения корректных вычислений размера окна. Чтобы создавать окна точного размера в других будущих реализациях API, вам нужно будет хранить небольшую библиотеку размеров браузерного интерфейса и использовать обнаружение браузера для определения браузера, рендеринга вашего приложения, и выбрать правильный размер для вычислений. Либо вы можете полагаться на менее точные размеры окна.

Обработка блокировщиков всплывающих окон браузера

В современных браузерах для каждого вызова Window.open() требуется отдельное событие пользовательского жеста по соображениям безопасности. Это предотвращает отправку сайтами множества окон пользователям. Однако это создает проблему для многооконных приложений. Чтобы обойти это ограничение, вы можете спроектировать свои приложения так:

  • Открывать не более одного нового окна за раз.
  • Использовать существующие окна для отображения различных страниц.
  • Предоставлять пользователям рекомендации по обновлению настроек браузера для разрешения нескольких окон.

В нашем демонстрационном приложении мы выбрали третий вариант. Наша функция openWindow() содержит следующий раздел:

// ...

if (windowRef === null) {
  // If the browser is blocking new windows, close any windows that were
  // able to open and display instructions to help the user fix this problem
  closeAllWindows();
  popoverElem.showPopover();
} else {
  // Store a reference to the window in the windowRefs array
  windowRefs.push(windowRef);
}

// ...

Если браузер заблокирует открытие нового окна, полученный результат windowRef будет null. В этом случае мы выполняем нашу функцию closeAllWindows() для закрытия всех окон, которые уже удалось открыть до начала блокировки, и отображаем элемент всплывающей подсказки, объясняющий, как отключить блокировщик всплывающих окон.

Простой случай с одним окном на дисплей

Если вы хотите открыть одно окно на каждом доступном дисплее, которое занимает всю ширину и высоту дисплея, вы можете использовать такой шаблон:

// Open a window on each screen of the device
for (const screen of screenDetails.screens) {
  openWindow(
    screen.availLeft,
    screen.availTop,
    screen.availWidth,
    screen.availHeight,
    url,
  );
}

События управления окнами

API управления окнами предоставляет некоторые события для реагирования на изменения доступных экранов:

Событие screenschange для объекта ScreenDetails

Срабатывает при подключении или отключении экранов от системы.

Событие currentscreenchange для ScreenDetails

Срабатывает при изменении текущего экрана окна.

Событие change для Screen

Срабатывает на определенном экране при его изменении.

Например, вы можете использовать событие screenschange для определения изменения доступных экранов (например, при подключении или отключении экрана), сообщения об изменениях, закрытия всех окон и обновления расположения окон в соответствии с новой конфигурацией:

screenDetails.addEventListener("screenschange", () => {
  // If the new number of screens is different to the old number of screens,
  // report the difference
  if (screenDetails.screens.length !== noOfScreens) {
    console.log(
      `The screen count changed from ${noOfScreens} to ${screenDetails.screens.length}`,
    );
  }

  // If the windows are open, close them and then open them again
  // So that they fit with the new screen configuration
  if (windowRefs.length > 0) {
    closeAllWindows();
    openWindows();
  }
});

Вариант requestFullscreen() для экрана

API управления окнами добавляет новый параметр screen к методу requestFullscreen(), который позволяет указать, на каком экране вы хотите поместить элемент в полноэкранный режим. Например, если вы хотите сделать это на главном экране ОС:

try {
  const primaryScreen = (await getScreenDetails()).screens.find(
    (screen) => screen.isPrimary,
  );
  await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
  console.error(err.name, err.message);
}

© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Window_Management_API/Using

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API