Uzyskuj informacje o połączonych wyświetlaczach i pozycjonuj okna względem tych wyświetlaczy.
Interfejs API zarządzania oknami
Interfejs Window Management API umożliwia wyliczenie wyświetlaczy podłączonych do komputera i rozmieszczanie okien na określonych ekranach.
Sugerowane przypadki użycia
Przykłady witryn, w których można używać tego interfejsu API:
- Edytory grafiki obsługujące wiele okien Gimp mogą umieszczać różne narzędzia do edytowania w precyzyjnie rozmieszczonych oknach.
- Wirtualne działy obrotu reklamami mogą pokazywać trendy rynkowe w wielu oknach, z których każdy może być wyświetlany w trybie pełnoekranowym.
- Aplikacje do pokazów slajdów mogą wyświetlać notatki prelegenta na wewnętrznym ekranie głównym i prezentację na projektorze zewnętrznym.
Jak korzystać z interfejsu Window Management API
Problem
Działające od lat podejście do sterowania oknami, Window.open()
, nie uwzględnia niestety dodatkowych ekranów. Niektóre aspekty tego interfejsu API, takie jak parametr windowFeatures
DOMString
, wydają się nieco przestarzałe, jednak na przestrzeni lat służą nam niesamowicie. Aby określić pozycję okna, możesz przekazać współrzędne jako left
i top
(lub odpowiednio screenX
i screenY
), a potem przekazać odpowiedni rozmiar jako width
i height
(lub odpowiednio innerWidth
i innerHeight
). Aby na przykład otworzyć okno 400 × 300 w odległości 50 pikseli od lewej i 50 pikseli od góry, 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
*/
Tak jak większość ludzi z branży technologicznej musiałam dostosować się do nowej sytuacji zawodowej i skonfigurować prywatne biuro domowe. Mój wygląd jest taki na zdjęciu poniżej (jeśli chcesz, możesz przeczytać pełne informacje o mojej konfiguracji). iPad obok MacBooka jest podłączony do laptopa przez Sidecar, więc w razie potrzeby mogę szybko zmienić go w drugi ekran.
Jeśli chcę wykorzystać większy ekran, mogę umieścić na drugim ekranie wyskakujące okienko z przykładowego kodu powyżej. Zrobię to w ten sposób:
popup.moveTo(2500, 50);
To może być przybliżone, ponieważ nie da się poznać wymiarów drugiego ekranu. Informacje z aplikacji window.screen
obejmują tylko wbudowany ekran, a nie ekran iPada. Zgłoszona wartość width
wbudowanego ekranu to 1680
piks., dlatego przejście do 2500
piks. może spowodować przesunięcie okna na iPada, bo wiem, że znajduje się on po prawej stronie mojego MacBooka. Jak to zrobić w praktyce? Okazuje się, że jest lepszy sposób niż zgadywanie. Jest to interfejs Window Management API.
Wykrywanie funkcji
Aby sprawdzić, czy interfejs Window Management API jest obsługiwany, użyj polecenia:
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
Uprawnienie window-management
Zanim będę mógł użyć interfejsu Window Management API, muszę poprosić użytkownika o pozwolenie.
Zapytanie o uprawnienie window-management
można wysłać za pomocą Permissions API, na przykład:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
Gdy korzystasz z przeglądarek ze starą i nową nazwą uprawnienia, pamiętaj o użyciu kodu zabezpieczającego, gdy prosisz o uprawnienia, tak jak w przykładzie poniżej.
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 wybrać dynamiczne wyświetlanie prośby o przyznanie uprawnień przy pierwszej próbie użycia dowolnej metody nowego interfejsu API. Czytaj dalej, aby dowiedzieć się więcej.
Właściwość window.screen.isExtended
Aby sprawdzić, czy z moim urządzeniem jest połączony więcej niż 1 ekran, otwieram właściwość window.screen.isExtended
. Zwraca true
lub false
. W mojej konfiguracji zwraca wartość true
.
window.screen.isExtended;
// Returns `true` or `false`.
Metoda getScreenDetails()
Skoro wiemy już, że bieżąca konfiguracja obejmuje wiele urządzeń, mogę więc uzyskać więcej informacji o drugim ekranie, korzystając z usługi Window.getScreenDetails()
. Wywołanie tej funkcji spowoduje wyświetlenie prośby o przyznanie uprawnień z pytaniem, czy witryna może otwierać i umieszczać okna na moim ekranie. Funkcja zwraca obietnicę, która kończy się obiektem ScreenDetailed
. Na moim MacBooku Pro 13 z połączonym iPadem
zawiera 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
w przypadku iPada zaczyna się od 1680
, co odpowiada dokładnie width
wbudowanemu wyświetlaczowi. Dzięki temu mogę określić, jak są logicznie rozmieszczone ekrany (obok siebie, jeden nad drugim itd.). Dostępne są też teraz dane dla każdego ekranu, które pokazują, czy jest to ekran isInternal
, a czy isPrimary
. Pamiętaj, że wbudowany ekran nie musi być ekranem głównym.
Pole currentScreen
to aktywny obiekt odpowiadający bieżącej wartości window.screen
. Obiekt jest aktualizowany w przypadku zmiany położenia okien na różnych ekranach lub zmian na urządzeniu.
Zdarzenie screenschange
Obecnie brakuje jedynie sposobu na wykrycie zmian w konfiguracji ekranu. Nowe zdarzenie – screenschange
– działa dokładnie tak samo: uruchamia się przy każdej zmianie konstelacji ekranu. (Zwróć uwagę, że „ekrany” w nazwie zdarzenia mają liczbę mnogą). Oznacza to, że zdarzenie jest wywoływane za każdym razem, gdy nowy ekran lub istniejący ekran jest (fizycznie lub wirtualnie w przypadku Sidecar) podłączony lub odłączony.
Pamiętaj, że nowe szczegóły ekranu musisz wyszukiwać asynchronicznie – samo zdarzenie screenschange
ich nie dostarcza. Aby wyszukać szczegóły ekranu, użyj aktywnego obiektu z interfejsu Screens
zapisanego 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 (tj. wartość aktywnego obiektu 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ę odsłuchać zdarzenie change
z 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 wymagać wyświetlania elementów w trybie pełnoekranowym za pomocą metody requestFullScreen()
o odpowiedniej nazwie. Metoda wykorzystuje parametr options
, za pomocą którego można przekazywać parametr FullscreenOptions
. Na razie jego jedyną usługą jest navigationUI
.
Interfejs Window Management API dodaje nową właściwość screen
, która pozwala określić, na którym ekranie rozpocząć widok pełnoekranowy. Jeśli na przykład chcesz ustawić pełny ekran
głównego ekranu:
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);
}
Włókno poliestrowe
Interfejsu Window Management API nie można wypełnić polyfill, ale możesz podłożyć jego kształt, aby kodować wyłącznie na podstawie 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;
}
Inne aspekty interfejsu API, czyli różne zdarzenia zmiany ekranu i właściwość screen
obiektu FullscreenOptions
, nie są po prostu uruchamiane lub są pomijane automatycznie przez nieobsługiwane przeglądarki.
Pokaz
Jeśli podobnie jak ja, uważnie obserwuję rozwój różnych kryptowalut. (W rzeczywistości bardzo nie lubię tej planety, ale w kontekście tego artykułu zakładam, że tak. Aby śledzić posiadane kryptowaluty, opracowałem aplikację internetową, która pozwala mi obserwować rynki w każdej sytuacji, np. gdy nie śpię w łóżku, gdzie mam przydatną konfigurację na jednym ekranie.
Jeśli chodzi o kryptowaluty, rynki mogą w każdej chwili stać się gorące. Jeśli tak się stanie, mogę szybko przejść do biurka i zainstalować urządzenie na wiele urządzeń. Mogę kliknąć okno dowolnej waluty, aby szybko zobaczyć szczegóły w widoku pełnoekranowym na drugim ekranie. Poniżej to moje ostatnie zdjęcie zrobione podczas ostatniej kąpieli YCY. Zupełnie odbiegłam od siebie i zostałam z rękami na twarzy.
Możesz pobawić się prezentacją umieszczoną poniżej lub zobaczyć jej kod źródłowy w razie usterek.
Zabezpieczenia i uprawnienia
Zespół Chrome zaprojektował i wdrożył interfejs Window Management API zgodnie z podstawowymi zasadami określonymi w artykule o kontrolowaniu dostępu do zaawansowanych funkcji platformy internetowej, takimi jak kontrola użytkownika, przejrzystość i ergonomia. Interfejs Window Management API udostępnia nowe informacje o ekranach połączonych z urządzeniem, co zwiększa powierzchnię odcisków palców użytkowników, zwłaszcza tych, którzy mają wiele ekranów stale połączonych z urządzeniami. Aby zminimalizować ryzyko naruszenia prywatności, ograniczyliśmy właściwości ujawnionych ekranów do minimum potrzebnego w typowych przypadkach użycia miejsc docelowych. Aby witryny mogły wyświetlać informacje o różnych ekranach i rozmieszczać okna na innych urządzeniach, uprawnienia użytkownika są wymagane. Chromium zwraca szczegółowe etykiety ekranu, ale przeglądarki mogą zwracać mniej opisowe (lub nawet puste etykiety).
Kontrola użytkowników
Użytkownik ma pełną kontrolę nad tym, jakie dane są widoczne w jego konfiguracji. Mogą zaakceptować lub odrzucić prośbę o uprawnienia, a także cofnąć wcześniej udzielone uprawnienia w sekcji informacji o witrynie w przeglądarce.
Kontrola firmy
Użytkownicy Chrome Enterprise mogą kontrolować kilka aspektów interfejsu Window Management API, jak opisano w odpowiedniej sekcji ustawień Atomic Policy Groups (Atomowe grupy zasad).
Przejrzystość
Informacja o tym, czy uprawnienie do korzystania z interfejsu Window Management API zostało przyznane, jest widoczne w informacjach o witrynie przeglądarki i można do niego wysyłać zapytania przy użyciu interfejsu Permissions API.
Trwałość uprawnień
Przeglądarka będzie nadal używała przyznanych uprawnień. Te uprawnienia można cofnąć, korzystając z informacji o witrynie w przeglądarce.
Prześlij opinię
Zespół Chrome chce poznać Twoją opinię na temat interfejsu Window Management API.
Opowiedz nam o projekcie interfejsu API
Czy interfejs API nie działa zgodnie z oczekiwaniami? A może brakuje metod lub właściwości, które potrzebujesz do realizacji swojego pomysłu? Masz pytanie lub komentarz na temat modelu bezpieczeństwa?
- Zgłoś problem ze specyfikacją w odpowiednim repozytorium GitHub lub dodaj swoje uwagi do istniejącego problemu.
Zgłoś problem z implementacją
Czy wystąpił błąd związany z implementacją przeglądarki Chrome? 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 odtworzenia i wpisz
Blink>Screen>MultiScreen
w polu Komponenty. Usterki to świetny sposób na udostępnianie szybkich i łatwych replik.
Pokaż obsługę interfejsu API
Czy zamierzasz użyć interfejsu Window Management API? Twoja publiczna pomoc pomaga zespołowi Chrome priorytetowo traktować funkcje i pokazuje innym dostawcom przeglądarek, jak ważne jest ich wsparcie.
- W wątku WICG Discourse napisz, jak zamierzasz korzystać z tego narzędzia.
- Wyślij tweeta na adres @ChromiumDev, używając hashtagu
#WindowManagement
, i daj nam znać, gdzie i do czego go używasz. - Poproś innych dostawców przeglądarek o wdrożenie interfejsu API.
Przydatne linki
- Wersja robocza specyfikacji
- Wyjaśnienie publiczne
- Prezentacja interfejsu Window Management API | Źródło demonstracyjne interfejsu Window Management API
- Błąd śledzenia w Chromium
- Wpis na ChromeStatus.com
- Komponent Blink:
Blink>Screen>MultiScreen
- Przegląd tagów
- Zamiar eksperymentu
Podziękowania
Specyfikację interfejsu Window Management API edytowali Victor Costan, Joshua Bell i Mike Wasserman. Interfejs API wdrożyli Mike Wasserman i Adrienne Walker. Ten artykuł napisali Joe Medley, François Beaufort i Kayce Basques. Dziękujemy Laurze Torrent Puig za zdjęcia.