uzyskiwać informacje o podłączonych wyświetlaczach i oknach w stosunku do tych wyświetlaczy;
Interfejs API zarządzania oknami
Interfejs Window Management API umożliwia zliczanie wyświetlaczy połączonych z urządzeniem oraz umieszczanie okien na określonych ekranach.
Sugerowane zastosowania
Przykłady witryn, które mogą korzystać z tego interfejsu API:
- Edytory grafiki z wieloma oknami w stylu Gimp mogą umieszczać różne narzędzia do edycji w precyzyjnie rozmieszczonych oknach.
- Wirtualne biura transakcyjne mogą wyświetlać trendy rynkowe w wielu oknach, z których każde można wyświetlić w trybie pełnoekranowym.
- Aplikacje do pokazów slajdów mogą wyświetlać notatki na wewnętrznym ekranie głównym, a prezentację na zewnętrznym projektorze.
Jak korzystać z interfejsu Window Management API
Problem
Działające od lat podejście do 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
, to przez lata dobrze nam służył. Aby określić położenie okna, możesz przekazać współrzędne jako left
i top
(odpowiednio screenX
i screenY
) oraz przekazać żądany rozmiar jako width
i height
(odpowiednio innerWidth
i innerHeight
). Jeśli na przykład chcesz otworzyć okno o wymiarach 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ć, korzystając z właściwości 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
*/
Podobnie jak większość osób pracujących w branży technologicznej musiałam dostosować się do nowej rzeczywistości i urządzić sobie prywatny gabinet w domu. Mój wygląda tak jak na zdjęciu poniżej (jeśli chcesz, możesz przeczytać szczegóły dotyczące mojego urządzenia). iPad obok MacBooka jest połączony z laptopem przez Sidecar, więc w razie potrzeby mogę szybko przekształcić iPada w drugi ekran.
Jeśli chcę skorzystać z większego ekranu, mogę umieścić wyskakujące okienko z przykładowego kodu powyżej na drugim ekranie. Robię to tak:
popup.moveTo(2500, 50);
To przybliżone przypuszczenie, bo nie można poznać wymiarów drugiego ekranu. Informacje z window.screen
dotyczą tylko wbudowanego ekranu, a nie ekranu iPada. Raportowany width
ekranu wbudowanego urządzenia to 1680
pikseli, więc przeniesienie do 2500
pikseli może pomóc w przesunięciu okna na iPada, ponieważ wiem, że znajduje się on po prawej stronie mojego MacBooka. Jak mogę to zrobić w ogóle? 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:
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
Uprawnienie window-management
Aby móc używać interfejsu Window Management API, muszę poprosić użytkownika o zgodę. Zapytanie window-management
można wysłać za pomocą Permissions API w następujący sposób:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
Chociaż używane są przeglądarki ze starą i nową nazwą uprawnienia, przy prośbie o uprawnienia należy używać kodu obronnego, tak 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 wyświetlić prośbę o uprawnienia dynamicznie przy pierwszej próbie użycia dowolnej metody nowego interfejsu API. Aby dowiedzieć się więcej, czytaj dalej.
Właściwość window.screen.isExtended
Aby sprawdzić, czy do mojego urządzenia jest podłączonych więcej niż 1 ekran, otwieram usługę window.screen.isExtended
. Zwraca true
lub false
. W moim przypadku zwraca on wartość true
.
window.screen.isExtended;
// Returns `true` or `false`.
Metoda getScreenDetails()
Teraz, gdy wiem, że bieżąca konfiguracja to konfiguracja wieloekranowa, mogę uzyskać więcej informacji o drugim ekranie, używając Window.getScreenDetails()
. Po wywołaniu tej funkcji wyświetli się prośba o uprawnienia, w której pytam, czy witryna może otwierać i umieszczać okna na moim ekranie. Funkcja zwraca obietnicę, która zwraca obiekt 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
na iPadzie zaczyna się od 1680
, co odpowiada dokładnie width
wbudowanego wyświetlacza. Pozwala mi to określić, jak dokładnie ekrany są logicznie rozmieszczone (obok siebie, jeden na drugim itp.). Dla każdego ekranu dostępne są teraz dane, które pokazują, czy ma on typ isInternal
, a także czy ma stan isPrimary
. Pamiętaj, że wbudowany ekran niekoniecznie jest ekranem głównym.
Pole currentScreen
jest aktywnym obiektem odpowiadającym bieżącemu obiektowi window.screen
. Obiekt jest aktualizowany w przypadku umieszczenia okna na różnych ekranach lub zmiany urządzenia.
Zdarzenie screenschange
Jedyną rzeczą, której brakuje, jest sposób wykrywania zmian w układzie ekranu. Nowe zdarzenie screenschange
działa właśnie w ten sposób: jest wywoływane, gdy nastąpi zmiana w konfiguracji ekranu. (Zwróć uwagę, że w nazwie zdarzenia „screens” występuje w formie liczby mnogiej.) Oznacza to, że zdarzenie jest wywoływane za każdym razem, gdy podłączysz lub odłączysz nowy lub istniejący ekran (fizycznie lub wirtualnie w przypadku aplikacji Sidecar).
Pamiętaj, że informacje o nowym ekranie musisz wyszukiwać asynchronicznie, ponieważ zdarzenie screenschange
samo w sobie nie zawiera tych danych. Aby sprawdzić szczegóły ekranu, użyj obiektu na żywo z interfejsu z pamięci podręcznejScreens
.
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 żywocurrentScreen
), 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
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 wysyłać prośby o wyświetlanie elementów w trybie pełnoekranowym za pomocą metody requestFullScreen()
o odpowiedniej nazwie. Metoda przyjmuje parametr options
, do którego możesz przekazać wartość FullscreenOptions
. Do tej pory jego jedyną usługą była usługa navigationUI
.
Interfejs Window Management API dodaje nową właściwość screen
, która pozwala określić, na którym ekranie chcesz włączyć 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
Nie można polyfillować interfejsu Window Management API, ale możesz użyć szablonu, aby móc kodować wyłącznie na potrzeby 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 byłyby wywoływane w nieobsługiwanych przeglądarkach lub byłyby ignorowane.
Prezentacja
Tak jak ja, uważnie przyglądacie się rozwojowi różnych kryptowalut. (W rzeczywistości nie chcę tego robić, ponieważ kocham tę planetę, ale na potrzeby tego artykułu załóżmy, że tak). Aby śledzić swoje kryptowaluty, stworzyłem aplikację internetową, która pozwala mi obserwować rynki w każdej sytuacji życiowej, np. z wygody łóżka, gdzie mam przyzwoite ustawienie z jednym ekranem.
Jeśli chodzi o kryptowaluty, na rynku panuje gwałtowny ruch w każdej chwili. W takiej sytuacji mogę szybko przeskoczyć do biurka, gdzie mam włączoną obsługę wielu ekranów. Mogę kliknąć okno dowolnej waluty i szybko wyświetlić pełne szczegóły w widoku pełnoekranowym na drugim ekranie. Poniżej znajduje się moje zdjęcie zrobione podczas ostatniego krwawawego pochodu YCY. Złapał mnie całkowicie nieprzygotowanego i umieścił moje ręce na twarzy.
Możesz wypróbować demo umieszczone poniżej lub sprawdzić kod źródłowy na stronie glitch.
Bezpieczeństwo i uprawnienia
Zespół Chrome zaprojektował i wdrożył interfejs Window Management API zgodnie z podstawowymi zasadami opisanymi w artykule Kontrola 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ę odcisku palca użytkowników, zwłaszcza tych, którzy mają wiele ekranów stale połączonych ze swoimi urządzeniami. Aby rozwiązać ten problem, ograniczyliśmy liczbę wyświetlanych właściwości ekranu do minimum potrzebnego w najczęstszych przypadkach użycia. Aby witryny mogły uzyskiwać informacje o wielu ekranach i rozmieszczać okna na innych ekranach, muszą mieć na to zgodę użytkownika. Podczas gdy Chromium zwraca szczegółowe etykiety ekranu, inne przeglądarki mogą zwracać mniej opisowe (lub nawet puste) etykiety.
Kontrola użytkowników
Użytkownik ma pełną kontrolę nad ekspozycją swojego urządzenia. Mogą zaakceptować lub odrzucić prośbę o zgodę i cofnąć wcześniej udzieloną zgodę za pomocą funkcji informacji o witrynie w przeglądarce.
Kontrola firmowa
Użytkownicy Chrome Enterprise mogą kontrolować kilka aspektów interfejsu Window Management API zgodnie z opisem w odpowiedniej sekcji ustawień Atomic Policy Groups (Atomowe grupy zasad).
Przejrzystość
Fakt przyznania uprawnień do korzystania z interfejsu Window Management API jest ujawniany w informacjach o witrynie w przeglądarce. Można też wysyłać do niego zapytania za pomocą interfejsu Permissions API.
Trwałość uprawnień
Przeglądarka zachowuje przyznane uprawnienia. Użytkownik może cofnąć zgodę w informacjach o witrynie przeglądarki.
Prześlij opinię
Zespół Chrome chce poznać Twoją opinię na temat korzystania z interfejsu Window Management API.
Prześlij informacje o projektowaniu interfejsu API
Czy jest coś, co nie działa w interfejsie API zgodnie z oczekiwaniami? A może brakuje metod lub właściwości, których potrzebujesz do wdrożenia swojego pomysłu? Masz pytania lub uwagi dotyczące modelu bezpieczeństwa?
- Zgłoś problem ze specyfikacją w odpowiednim repozytorium GitHub lub dodaj swoje uwagi do istniejącego problemu.
Zgłaszanie problemów z implementacją
Czy znalazłeś/znalazłaś błąd w implementacji 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 odtwarzania błędu i wpisz
Blink>Screen>MultiScreen
w polu Components. Usługa Glitch świetnie nadaje się do szybkiego i łatwego udostępniania poprawek.
Pokaż wsparcie dla interfejsu API
Czy planujesz skorzystać z interfejsu Window Management API? Twoja publiczna pomoc pomaga zespołowi Chrome ustalać priorytety funkcji i pokazuje innym dostawcom przeglądarek, jak ważne jest wspieranie tych funkcji.
- Daj znać, jak zamierzasz korzystać z tego narzędzia w wątku poświęconym dysku WICG.
- Wyślij tweeta do @ChromiumDev, używając hashtaga
#WindowManagement
, i podaj, gdzie i jak z niego korzystasz. - Poproś innych dostawców przeglądarek o wdrożenie interfejsu API.
Przydatne linki
- Specyfikacja w wersji roboczej
- Publiczny film wyjaśniający
- Demo interfejsu Window Management API | demo interfejsu Window Management API
- Błąd śledzenia w Chromium
- Wpis na stronie ChromeStatus.com
- Składnik Blink:
Blink>Screen>MultiScreen
- Sprawdzanie tagów
- Zamiar eksperymentowania
Podziękowania
Specyfikację interfejsu Window Management API opracowali Victor Costan, Joshua Bell i Mike Wasserman. Interfejs API został wdrożony przez Mike’a Wassermana i Adrienne Walker. Ten artykuł został sprawdzony przez Joe Medley, François Beaufort i Kayce Basques. Dziękujemy Laurze Torrent Puig za zdjęcia.