uzyskiwać informacje o podłączonych wyświetlaczach i pozycjonować okna względem nich;
Window Management API
Interfejs Window Management API umożliwia wyliczanie wyświetlaczy podłączonych do urządzenia i umieszczanie okien na określonych ekranach.
Sugerowane przypadki użycia
Przykłady witryn, które mogą korzystać z tego interfejsu API:
- Edytory graficzne z wieloma oknami, takie jak GIMP, mogą umieszczać różne narzędzia do edycji w dokładnie określonych oknach.
- Wirtualne platformy handlowe mogą wyświetlać trendy rynkowe w wielu oknach, z których każde można wyświetlić w trybie pełnoekranowym.
- Aplikacje do prezentacji mogą wyświetlać notatki prelegenta na wewnętrznym ekranie głównym, a prezentację na zewnętrznym projektorze.
Jak korzystać z interfejsu Window Management API
Problem
Sprawdzony sposób sterowania oknami,Window.open()
niestety, nie uwzględnia dodatkowych ekranów. Chociaż niektóre aspekty tego interfejsu API wydają się nieco przestarzałe, np. parametr windowFeatures
DOMString
, przez lata dobrze nam służył. Aby określić położenie okna, możesz przekazać współrzędne jako left
i top
(lub odpowiednio screenX
i screenY
), a żądany rozmiar jako width
i height
(lub odpowiednio innerWidth
i innerHeight
). Jeśli na przykład chcesz otworzyć okno o wymiarach 400 × 300 pikseli w odległości 50 pikseli od lewej i 50 pikseli od górnej krawędzi, możesz użyć tego kodu:
const popup = window.open(
'https://example.com/',
'My Popup',
'left=50,top=50,width=400,height=300',
);
Informacje o bieżącym ekranie możesz uzyskać, sprawdzając właściwość window.screen
, która zwraca obiekt Screen
. Oto dane wyjściowe na moim MacBooku Pro 13″:
window.screen;
/* Output from my MacBook Pro 13″:
availHeight: 969
availLeft: 0
availTop: 25
availWidth: 1680
colorDepth: 30
height: 1050
isExtended: true
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 30
width: 1680
*/
Jak większość osób pracujących w branży technologicznej musiałem dostosować się do nowej rzeczywistości i urządzić sobie domowe biuro. Mój wygląda tak jak na zdjęciu poniżej (jeśli chcesz, możesz przeczytać szczegółowe informacje o mojej konfiguracji). iPad obok MacBooka jest połączony z laptopem za pomocą funkcji Sidecar, więc w razie potrzeby mogę szybko przekształcić iPada w drugi ekran.

Jeśli chcę skorzystać z większego ekranu, mogę przenieść wyskakujące okienko z przykładowego kodu powyżej na drugi ekran. Robię to tak:
popup.moveTo(2500, 50);
To tylko przybliżone oszacowanie, ponieważ nie ma możliwości poznania wymiarów drugiego ekranu. Informacje z window.screen
obejmują tylko wbudowany ekran, a nie ekran iPada. Zgłoszona width
wartość wbudowanego ekranu wynosiła 1680
pikseli, więc przejście na 2500
pikseli może przesunąć okno na iPada, ponieważ wiem, że znajduje się on po prawej stronie mojego MacBooka. Jak mogę to zrobić w przypadku ogólnym? Okazuje się, że istnieje lepszy sposób niż zgadywanie. Jest to interfejs Window Management API.
Wykrywanie cech
Aby sprawdzić, czy interfejs Window Management API jest obsługiwany, użyj tego kodu:
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
Uprawnienie window-management
Zanim będę mógł używać interfejsu Window Management API, muszę poprosić użytkownika o zgodę na to. O uprawnienie window-management
można zapytać za pomocą interfejsu Permissions API w ten sposób:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
Dopóki przeglądarki z nową i starą nazwą uprawnień są w użyciu, podczas przesyłania prośby o uprawnienia używaj kodu defensywnego, jak w poniższym przykładzie.
async function getWindowManagementPermissionState() {
let state;
// The new permission name.
try {
({ state } = await navigator.permissions.query({
name: "window-management",
}));
} catch (err) {
return `${err.name}: ${err.message}`;
}
return state;
}
document.querySelector("button").addEventListener("click", async () => {
const state = await getWindowManagementPermissionState();
document.querySelector("pre").textContent = state;
});
Przeglądarka może dynamicznie wyświetlać prośbę o przyznanie uprawnień przy pierwszej próbie użycia dowolnej metody nowego interfejsu API. Czytaj dalej, aby dowiedzieć się więcej.
Usługa window.screen.isExtended
Aby sprawdzić, czy do mojego urządzenia jest podłączony więcej niż 1 ekran, otwieram właściwość window.screen.isExtended
. Zwraca wartość true
lub false
. W moim przypadku zwraca wartość true
.
window.screen.isExtended;
// Returns `true` or `false`.
Metoda getScreenDetails()
Teraz, gdy wiem, że bieżąca konfiguracja obejmuje wiele ekranów, mogę uzyskać więcej informacji o drugim ekranie za pomocą Window.getScreenDetails()
. Wywołanie tej funkcji spowoduje wyświetlenie prośby o uprawnienia, w której użytkownik zostanie zapytany, czy witryna może otwierać i umieszczać okna na jego ekranie. Funkcja zwraca obietnicę, która jest spełniana przez obiekt ScreenDetailed
. Na moim MacBooku Pro 13 z podłączonym iPadem obejmuje to pole screens
z 2 obiektami ScreenDetailed
:
await window.getScreenDetails();
/* Output from my MacBook Pro 13″ with the iPad attached:
{
currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …}
oncurrentscreenchange: null
onscreenschange: null
screens: [{
// The MacBook Pro
availHeight: 969
availLeft: 0
availTop: 25
availWidth: 1680
colorDepth: 30
devicePixelRatio: 2
height: 1050
isExtended: true
isInternal: true
isPrimary: true
label: "Built-in Retina Display"
left: 0
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 30
top: 0
width: 1680
},
{
// The iPad
availHeight: 999
availLeft: 1680
availTop: 25
availWidth: 1366
colorDepth: 24
devicePixelRatio: 2
height: 1024
isExtended: true
isInternal: false
isPrimary: false
label: "Sidecar Display (AirPlay)"
left: 1680
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 24
top: 0
width: 1366
}]
}
*/
Informacje o połączonych ekranach są dostępne w tablicy screens
. Zwróć uwagę, że wartość left
na iPadzie zaczyna się od 1680
, czyli dokładnie od width
wbudowanego wyświetlacza. Dzięki temu mogę dokładnie określić, jak ekrany są rozmieszczone logicznie (obok siebie, jeden na drugim itp.). Dostępne są też dane dotyczące każdego ekranu, które pokazują, czy jest on isInternal
, czy isPrimary
. Pamiętaj, że wbudowany ekran nie musi być ekranem głównym.
Pole currentScreen
to aktywny obiekt odpowiadający bieżącemu window.screen
. Obiekt jest aktualizowany w przypadku umieszczeń w oknach na różnych ekranach lub zmian urządzeń.
Zdarzenie screenschange
Brakuje tylko sposobu wykrywania zmian w konfiguracji ekranu. Nowe zdarzenie,
screenschange
, robi dokładnie to: uruchamia się za każdym razem, gdy zmienia się konfiguracja ekranu. (Zwróć uwagę, że w nazwie zdarzenia „screens” jest w liczbie mnogiej). Oznacza to, że zdarzenie jest wywoływane za każdym razem, gdy nowy ekran lub istniejący ekran (fizycznie lub wirtualnie w przypadku Sidecar) jest podłączany lub odłączany.
Pamiętaj, że szczegóły nowego ekranu musisz wyszukać asynchronicznie. Samo zdarzenie screenschange
nie zawiera tych danych. Aby sprawdzić szczegóły ekranu, użyj obiektu na żywo z interfejsu Screens
w pamięci podręcznej.
const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
screenDetails.addEventListener('screenschange', (event) => {
if (screenDetails.screens.length !== cachedScreensLength) {
console.log(
`The screen count changed from ${cachedScreensLength} to ${screenDetails.screens.length}`,
);
cachedScreensLength = screenDetails.screens.length;
}
});
Zdarzenie currentscreenchange
Jeśli interesują mnie tylko zmiany na bieżącym ekranie (czyli wartość obiektu na żywo
currentScreen
), mogę nasłuchiwać zdarzenia currentscreenchange
.
const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
const details = screenDetails.currentScreen;
console.log('The current screen has changed.', event, details);
});
Zdarzenie change
Jeśli interesują mnie tylko zmiany na konkretnym ekranie, mogę nasłuchiwać zdarzenia change
tego ekranu.
const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
console.log('The first screen has changed.', event, firstScreen);
});
Nowe opcje pełnego ekranu
Do tej pory można było poprosić o wyświetlenie elementów w trybie pełnoekranowym za pomocą metody o odpowiedniej nazwie
requestFullScreen()
. Metoda przyjmuje parametr options
, w którym możesz przekazać FullscreenOptions
. Do tej pory jedyną właściwością tej usługi była navigationUI
.
Interfejs Window Management API dodaje nową właściwość screen
, która pozwala określić, na którym ekranie ma się rozpocząć widok pełnoekranowy. Jeśli na przykład chcesz wyświetlić ekran główny na pełnym ekranie:
try {
const primaryScreen = (await getScreenDetails()).screens.filter((screen) => screen.isPrimary)[0];
await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
console.error(err.name, err.message);
}
Watolina poliestrowa
Nie można zastosować polyfillu do interfejsu Window Management API, ale możesz zastosować shim do jego kształtu, aby pisać kod wyłącznie pod kątem nowego interfejsu API:
if (!('getScreenDetails' in window)) {
// Returning a one-element array with the current screen,
// noting that there might be more.
window.getScreenDetails = async () => [window.screen];
// Set to `false`, noting that this might be a lie.
window.screen.isExtended = false;
}
Pozostałe aspekty interfejsu API, czyli różne zdarzenia zmiany ekranu i właściwość screen
elementu FullscreenOptions
, nigdy nie będą wywoływane lub będą cicho ignorowane przez przeglądarki, które nie obsługują tej funkcji.
Prezentacja
Jeśli jesteś podobny do mnie, uważnie śledzisz rozwój różnych kryptowalut. (W rzeczywistości bardzo mi na niej zależy, ale na potrzeby tego artykułu załóżmy, że tak nie jest). Aby śledzić posiadane kryptowaluty, stworzyłem aplikację internetową, która umożliwia mi obserwowanie rynków w każdej sytuacji, np. w wygodnym łóżku, gdzie mam przyzwoity zestaw z jednym ekranem.

Ponieważ chodzi o kryptowaluty, rynki mogą w każdej chwili stać się niestabilne. W takiej sytuacji mogę szybko przejść do biurka, gdzie mam konfigurację z wieloma ekranami. Mogę kliknąć okno dowolnej waluty i szybko wyświetlić wszystkie szczegóły w widoku pełnoekranowym na przeciwnym ekranie. Poniżej znajduje się moje ostatnie zdjęcie zrobione podczas ostatniej rzezi YCY. Zaskoczyło mnie to całkowicie i zostałem z rękami na twarzy.

Możesz wypróbować wersję demonstracyjną poniżej lub zobaczyć jej kod źródłowy na GitHubie.
Zabezpieczenia i uprawnienia
Zespół Chrome zaprojektował i wdrożył interfejs Window Management API zgodnie z głównymi zasadami określonymi w dokumencie Controlling Access to Powerful Web Platform Features, w tym z zasadami dotyczącymi kontroli użytkownika, przejrzystości i ergonomii. Interfejs Window Management API udostępnia nowe informacje o ekranach podłączonych do urządzenia, co zwiększa obszar odcisków cyfrowych użytkowników, zwłaszcza tych, którzy mają wiele ekranów stale podłączonych do swoich urządzeń. Aby ograniczyć to zagrożenie dla prywatności, udostępniane właściwości ekranu są ograniczone do minimum niezbędnego w przypadku typowych miejsc docelowych. Aby witryny mogły uzyskiwać informacje o wielu ekranach i umieszczać okna na innych ekranach, wymagana jest zgoda użytkownika. Chromium zwraca szczegółowe etykiety ekranu, ale inne przeglądarki mogą zwracać mniej opisowe etykiety (lub nawet puste).
Kontrola sprawowana przez użytkowników
Użytkownik ma pełną kontrolę nad tym, jak jego konfiguracja jest widoczna. Mogą zaakceptować lub odrzucić prośbę o uprawnienia oraz cofnąć wcześniej przyznane uprawnienia za pomocą funkcji informacji o witrynie w przeglądarce.
Kontrola w firmie
Użytkownicy Chrome Enterprise mogą kontrolować różne aspekty interfejsu Window Management API, jak opisano w odpowiedniej sekcji ustawień atomowych grup zasad.
Przejrzystość
Informacja o tym, czy przyznano uprawnienia do korzystania z interfejsu Window Management API, jest widoczna w informacjach o witrynie w przeglądarce i można ją też uzyskać za pomocą interfejsu Permissions API.
Trwałość uprawnień
Przeglądarka zachowuje przyznane uprawnienia. Zezwolenie można cofnąć w informacjach o witrynie w przeglądarce.
Prześlij opinię
Zespół Chrome chce poznać Twoje wrażenia związane z korzystaniem z interfejsu Window Management API.
Opisz projekt interfejsu API
Czy coś w API nie działa tak, jak oczekujesz? Czy brakuje metod lub właściwości, które są potrzebne do realizacji Twojego pomysłu? Masz pytania lub uwagi dotyczące modelu zabezpieczeń?
- Zgłoś problem ze specyfikacją w odpowiednim repozytorium GitHub lub dodaj swoje uwagi do istniejącego problemu.
Zgłaszanie problemu z implementacją
Czy w implementacji Chrome występuje błąd? A może implementacja różni się od specyfikacji?
- Zgłoś błąd na stronie new.crbug.com. Podaj jak najwięcej szczegółów, proste instrukcje odtwarzania i wpisz
Blink>Screen>MultiScreen
w polu Komponenty.
Wyrażanie poparcia dla interfejsu API
Czy planujesz używać interfejsu Window Management API? Twoje publiczne wsparcie pomaga zespołowi Chrome ustalać priorytety funkcji i pokazuje innym dostawcom przeglądarek, jak ważne jest ich obsługiwanie.
- Opisz, jak zamierzasz z niej korzystać, w wątku na forum WICG Discourse.
- Wyślij tweeta do @ChromiumDev z hasztagiem
#WindowManagement
i napisz, gdzie i jak korzystasz z tej funkcji. - Poproś innych dostawców przeglądarek o wdrożenie interfejsu API.
Przydatne linki
- Wersja robocza specyfikacji
- Wyjaśnienie publiczne
- Demo interfejsu Window Management API | Demo interfejsu Window Management API source
- Błąd śledzenia w Chromium
- Wpis na ChromeStatus.com
- Komponent Blink:
Blink>Screen>MultiScreen
- Sprawdzanie przez TAG
- Zamiar przeprowadzenia eksperymentu
Podziękowania
Specyfikację interfejsu Window Management API edytowali Victor Costan, Joshua Bell i Mike Wasserman. Interfejs API został wdrożony przez Mike’a Wassermana i Adrienne Walker. Ten artykuł został sprawdzony przez Joego Medleya, François Beauforta i Kayce Basques. Dziękujemy Laurze Torrent Puig za zdjęcia.