取得已連接螢幕和定位視窗相對於螢幕的資訊。
Window Management API
Window Management API 可讓您列舉連線至機器的螢幕,並在特定畫面中放置視窗。
建議用途
可能使用此 API 的網站範例包括:
- 多視窗圖形編輯器 (Gimp) 可將各種編輯工具放入正確定位的視窗中。
- 虛擬交易桌面可顯示多個視窗中的市場趨勢,而且可在全螢幕模式下查看。
- 投影播放應用程式可在內部主螢幕顯示演講者備忘稿,以及在外部投影機上顯示簡報。
如何使用 Window Management API
問題所在
過去經過時間測試來控制視窗的方法 Window.open()
,可惜不知道還有哪些螢幕。雖然這個 API 的某些面向似乎很有意義,例如其 windowFeatures
DOMString
參數,但我們多年來一直提供這項服務。若要指定視窗的位置,您可以將座標以 left
和 top
(或 screenX
和 screenY
) 的形式傳遞,並將所需大小做為 width
和 height
(或 innerWidth
和 innerHeight
) 傳遞。舉例來說,如要開啟距離左側 50 像素、距離頂端 50 像素的 400×300 視窗,您可以使用以下程式碼:
const popup = window.open(
'https://example.com/',
'My Popup',
'left=50,top=50,width=400,height=300',
);
您可以查看傳回 Screen
物件的 window.screen
屬性,取得目前畫面的相關資訊。這是 MacBook 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
*/
我和大多數科技業人員一樣,必須適應新的工作方式,並且設立個人家庭辦公室。我的相片看起來像下面這樣的相片 (如有需要,請參閱「設定的完整詳細資料」)。 我 MacBook 旁的 iPad 會透過補充資訊連接至筆記型電腦,因此每當我需要,我可以快速將 iPad 轉到第二個螢幕。
如果想要利用更大的螢幕,我可以把上述程式碼範例中的彈出式視窗放在第二個畫面。方法如下:
popup.moveTo(2500, 50);
由於無法得知第二個畫面的尺寸,因此這項估計值。window.screen
的資訊僅涵蓋內建畫面,不包括 iPad 螢幕。回報的內建螢幕 width
是 1680
像素,因此改用 2500
像素後,可能會將視窗轉移至 iPad,因為「我」得知它位於 MacBook 的右側。一般情況下,我該怎麼做?反之,有更好的方法可以猜測。這樣就是 Window Management API。
功能偵測
如要確認 Window Management API 是否受支援,請使用:
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
window-management
權限
我必須先要求使用者授予相關權限,才能使用 Window Management API。您可以透過 Permissions API 查詢 window-management
權限,如下所示:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
如果使用舊版和新權限名稱的瀏覽器,在要求權限時請務必使用防禦程式碼,如以下範例所示。
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;
});
瀏覽器可以選擇在第一次嘗試使用任何新 API 方法時,動態顯示權限提示。請繼續閱讀以瞭解詳情。
window.screen.isExtended
屬性
如果想確認我的裝置是否連結了多個螢幕,我可以存取 window.screen.isExtended
屬性。其會傳回 true
或 false
。根據我的設定,它會傳回 true
。
window.screen.isExtended;
// Returns `true` or `false`.
getScreenDetails()
方法
現在,我知道目前設定為多螢幕設定,現在可以使用 Window.getScreenDetails()
取得第二個畫面的詳細資訊。呼叫此函式會顯示權限提示,詢問網站是否可開啟並在螢幕上放置視窗。這個函式會傳回承諾,該承諾會透過 ScreenDetailed
物件解析。在已連接 iPad 的 MacBook Pro 13 中,這會包含具有兩個 ScreenDetailed
物件的 screens
欄位:
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
}]
}
*/
您可以在 screens
陣列中找到已連結畫面的相關資訊。請注意,iPad 的 left
值會從 1680
開始,這與內建螢幕的 width
完全相同。這可讓我準確判斷畫面在邏輯上排列的方式 (彼此相鄰、彼此重疊等等)。現在每個畫面也都有資料,可指出它是否為 isInternal
類型,以及是否為 isPrimary
。請注意,內建畫面不一定是主畫面。
currentScreen
欄位是與目前 window.screen
對應的使用中物件。跨螢幕視窗刊登位置或裝置變更時,物件會隨之更新。
screenschange
事件
目前唯一缺少的功能是偵測螢幕設定何時變更的方法。新事件 screenschange
正好能夠達成這個目標:每當螢幕全景圖修改時,就會觸發這個事件。(請注意,事件名稱中的「Screen」是複數)。這表示每當新畫面或現有畫面 (在「邊車」) 接上或未接上電源時,就會觸發事件。
請注意,您需要以非同步方式查詢新畫面的詳細資料,screenschange
事件本身不會提供這項資料。如要查詢螢幕詳細資料,請使用快取 Screens
介面中的使用中物件。
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;
}
});
currentscreenchange
事件
如果我只想變更目前畫面 (也就是使用中物件 currentScreen
的值),則可以監聽 currentscreenchange
事件。
const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
const details = screenDetails.currentScreen;
console.log('The current screen has changed.', event, details);
});
change
事件
最後,如果我只想變更具體螢幕,可以監聽該畫面的 change
事件。
const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
console.log('The first screen has changed.', event, firstScreen);
});
新的全螢幕選項
目前,您可以使用重新命名的 requestFullScreen()
方法,要求元素以全螢幕模式顯示。此方法使用 options
參數,您可以在其中傳遞 FullscreenOptions
。目前為止,其唯一屬性是 navigationUI
。Window Management API 新增了 screen
屬性,可讓您決定要在哪個畫面啟動全螢幕檢視畫面。舉例來說,如果想將主畫面設為全螢幕:
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);
}
聚酯纖維
您無法為 Window Management API 建立折線,但可以調整其形狀,以便只針對新的 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;
}
API 的其他層面 (即各種螢幕變更事件和 FullscreenOptions
的 screen
屬性) 絕不會被不支援瀏覽器個別觸發,也不會自動忽略。
操作示範
如果你像我一樣,密切留意各種加密貨幣的開發過程。(事實上,我其實並非因為我很喜歡這個星球,但為了閱讀本文,就先假裝自己知道了)。為了持續追蹤我擁有的加密貨幣,我開發了一款網頁應用程式,能夠在各種情況下觀看市場趨勢,例如在床上舒適地進行單一螢幕配置。
不只是加密貨幣,市場隨時都可能生硬。發生這種情況時 我可以快速移到我的辦公桌上,開始設置多螢幕設定我只要點一下任何貨幣視窗,用全螢幕畫面 就能快速查看完整詳細資料以下是我在過去 YCY 血巴期間拍攝的近期相片。它吸引我完全沒有警覺,然後將我的手放在我的臉上。
你可以利用下方的嵌入式示範來試玩,也可以檢查是否有故障的原始碼。
安全性和權限
Chrome 團隊根據「控管強大的網路平台功能存取權」一文中定義的核心原則 (包括使用者控制項、資訊公開和人體工學) 設計及實作 Window Management API。Window Management API 會公開與裝置連線畫面相關的新資訊,進而增加使用者的指紋辨識途徑,尤其是擁有多個螢幕持續與其裝置連線的使用者。為緩解這項隱私權疑慮,暴露畫面屬性僅限於常見刊登位置用途所需的最低限度。網站必須取得使用者權限,才能取得多螢幕資訊,並將視窗放在其他畫面上。雖然 Chromium 會傳回詳細的畫面標籤,但瀏覽器可自由傳回較不的說明內容 (甚至是空白標籤)。
使用者控制項
使用者可以完全掌控是否要啟用這項設定。他們可以接受或拒絕權限提示,也能透過瀏覽器的網站資訊功能,撤銷先前授予的權限。
企業控管
Chrome Enterprise 使用者可以控制 Window Management API 的多個方面,相關說明請參閱「原子政策群組」設定的相關章節。
資訊公開
瀏覽器的網站資訊中是否會顯示授予 Window Management API 使用權限,使用者也可以透過 Permissions API 進行查詢。
權限持續性
瀏覽器會維持授予的權限。您可以透過瀏覽器的網站資訊撤銷權限。
意見回饋:
Chrome 團隊想瞭解您的 Window Management API 使用體驗。
告訴我們 API 設計
有什麼 API 功能不如您預期嗎?或者您需要實作提案的方法或屬性嗎?對於安全性模型有任何疑問或意見嗎?
- 在對應的 GitHub 存放區上提交規格問題,或是將您的想法新增至現有問題。
回報導入問題
您在執行 Chrome 時發現錯誤了嗎?或者實作與規格不同?
- 請前往 new.crbug.com 回報錯誤。請務必盡可能提供詳細的細節、簡單的重現操作說明,並在「Components」(元件) 方塊中輸入
Blink>Screen>MultiScreen
。Glitch 適合用來快速分享簡單快速的提案,
展現對 API 的支援
您打算使用 Window Management API 嗎?您的公開支援可協助 Chrome 團隊排定功能的優先順序,讓其他瀏覽器廠商瞭解這些功能對他們的支援程度有多重要。
- 請在 WICG Discourse 討論串上分享計畫使用方式。
- 請使用主題標記
#WindowManagement
將 Tweet 訊息傳送至 @ChromiumDev,並告訴我們您的使用地點和方式。 - 要求其他瀏覽器廠商實作 API。
實用連結
- 規格草稿
- 公開說明
- Window Management API 示範 | Window Management API 示範來源
- Chromium 追蹤錯誤
- ChromeStatus.com 項目
- 閃爍元件:
Blink>Screen>MultiScreen
- TAG 審查
- 實驗意願
特別銘謝
Window Management API 規格是由 Victor Costan、Joshua Bell 和 Mike Wasserman 編輯。這個 API 是由 Mike Wasserman 和 Adrienne Walker 實作。本文由 Joe Medley、François Beaufort 和 Kayce Basques 審查。感謝 Laura Torrent Puig 提供相片。