จัดการจอแสดงผลหลายจอด้วย Window Management API

รับข้อมูลเกี่ยวกับจอแสดงผลที่เชื่อมต่อและวางตำแหน่งหน้าต่างที่สัมพันธ์กับจอแสดงผลเหล่านั้น

เผยแพร่: 14 กันยายน 2020

Window Management API

Window Management API ช่วยให้คุณแสดงรายการจอแสดงผลที่เชื่อมต่อกับเครื่องและวางหน้าต่างบนหน้าจอที่เฉพาะเจาะจงได้

กรณีการใช้งานที่แนะนำ

ตัวอย่างเว็บไซต์ที่อาจใช้ API นี้ ได้แก่

  • โปรแกรมแก้ไขกราฟิกแบบหลายหน้าต่างอย่าง Gimp สามารถวางเครื่องมือแก้ไขต่างๆ ในหน้าต่างที่วางตำแหน่งอย่างแม่นยำ
  • โต๊ะซื้อขายเสมือนจะแสดงแนวโน้มของตลาดในหลายหน้าต่าง ซึ่งดูได้ใน โหมดเต็มหน้าจอ
  • แอปสไลด์โชว์สามารถแสดงบันทึกของผู้บรรยายบนหน้าจอหลักภายในและงานนำเสนอบน โปรเจ็กเตอร์ภายนอก

วิธีใช้ Window Management API

แต่น่าเสียดายที่วิธีการควบคุมหน้าต่างที่ใช้กันมานานอย่าง Window.open() ไม่รู้จักหน้าจอเพิ่มเติม แม้ว่าบางแง่มุมของ API นี้อาจดูเก่าไปบ้าง เช่น พารามิเตอร์ windowFeatures DOMString แต่ก็ยังคงใช้งานได้ดีตลอดหลายปีที่ผ่านมา หากต้องการระบุตำแหน่งของหน้าต่าง คุณสามารถส่งพิกัดเป็น left และ top (หรือ screenX และ screenY ตามลำดับ) และส่งขนาดที่ต้องการเป็น width และ height (หรือ innerWidth และ innerHeight ตามลำดับ) ตัวอย่างเช่น หากต้องการเปิดหน้าต่างขนาด 400×300 ที่ 50 พิกเซลจากด้านซ้ายและ 50 พิกเซลจากด้านบน คุณสามารถใช้โค้ดต่อไปนี้

const popup = window.open(
  'https://example.com/',
  'My Popup',
  'left=50,top=50,width=400,height=300',
);

คุณดูข้อมูลเกี่ยวกับหน้าจอปัจจุบันได้โดยดูที่พร็อพเพอร์ตี้ window.screen ซึ่ง จะแสดงผลออบเจ็กต์ 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
*/

เช่นเดียวกับคนส่วนใหญ่ที่ทำงานด้านเทคโนโลยี ฉันต้องปรับตัวให้เข้ากับความเป็นจริงของการทำงานในปี 2020 และจัดตั้งโฮมออฟฟิศส่วนตัว ของฉันมีลักษณะดังในรูปภาพ (หากสนใจ คุณสามารถอ่านรายละเอียดทั้งหมดเกี่ยวกับการตั้งค่าของฉัน) iPad ที่อยู่ข้าง MacBook ของฉันเชื่อมต่อกับแล็ปท็อปผ่าน Sidecar ดังนั้นเมื่อใดก็ตามที่ต้องการ ฉันก็เปลี่ยน iPad ให้เป็นหน้าจอที่ 2 ได้อย่างรวดเร็ว

ม้านั่งของโรงเรียนวางอยู่บนเก้าอี้ 2 ตัว บนม้านั่งของโรงเรียนมีกล่องรองเท้าที่รองรับแล็ปท็อปและ iPad 2 เครื่องที่อยู่รอบๆ
การตั้งค่าหลายหน้าจอ

หากต้องการใช้ประโยชน์จากหน้าจอที่ใหญ่ขึ้น ฉันสามารถวางป๊อปอัปจากโค้ดตัวอย่างลงในหน้าจอที่ 2 ได้ ฉันทำแบบนี้

popup.moveTo(2500, 50);

นี่เป็นการคาดคะเนคร่าวๆ เนื่องจากไม่มีวิธีทราบขนาดของหน้าจอที่ 2 ข้อมูล จาก 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 ได้ ฉันต้องขอสิทธิ์จากผู้ใช้ก่อน คุณสามารถค้นหาสิทธิ์ window-management ได้ด้วย Permissions API ดังนี้

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

หากต้องการดูว่ามีหน้าจอมากกว่า 1 จอเชื่อมต่อกับอุปกรณ์ของฉันหรือไม่ ฉันจะเข้าถึงพร็อพเพอร์ตี้ window.screen.isExtended โดยจะแสดงผลเป็น true หรือ false สำหรับการตั้งค่าของฉัน ระบบจะแสดง true

window.screen.isExtended;
// Returns `true` or `false`.

getScreenDetails() วิธี

ตอนนี้ฉันรู้แล้วว่าการตั้งค่าปัจจุบันเป็นแบบหลายหน้าจอ ฉันจึงสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับ หน้าจอที่ 2 ได้โดยใช้ Window.getScreenDetails() การเรียกใช้ฟังก์ชันนี้จะแสดงข้อความแจ้งขอสิทธิ์ที่ ถามว่าเว็บไซต์เปิดและวางหน้าต่างบนหน้าจอได้ไหม ฟังก์ชันจะแสดงผล Promise ที่แก้ไขด้วยออบเจ็กต์ ScreenDetailed ใน MacBook Pro 13 ที่เชื่อมต่อกับ iPad จะมีscreensฟิลด์ที่มีออบเจ็กต์ ScreenDetailed 2 รายการดังนี้

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 โปรดสังเกตว่าค่าของ left สำหรับ iPad เริ่มต้นที่ 1680 ซึ่งตรงกับ width ของจอแสดงผลในตัว ซึ่งช่วยให้ฉันระบุได้ว่าหน้าจอต่างๆ จัดเรียงกันอย่างไรในเชิงตรรกะ (อยู่ข้างกัน อยู่ซ้อนกัน ฯลฯ) นอกจากนี้ ตอนนี้ยังมีข้อมูลสำหรับแต่ละหน้าจอเพื่อแสดงว่าหน้าจอนั้นเป็นisInternal และเป็นisPrimaryหรือไม่ โปรดทราบว่าหน้าจอในตัวไม่จำเป็นต้องเป็นหน้าจอหลัก

currentScreen คือออบเจ็กต์ที่ใช้งานจริงซึ่งสอดคล้องกับ window.screen ปัจจุบัน ออบเจ็กต์ จะได้รับการอัปเดตเมื่อมีการจัดวางหน้าต่างข้ามหน้าจอหรือมีการเปลี่ยนแปลงอุปกรณ์

การแข่งขัน screenschange

ตอนนี้เหลือเพียงวิธีตรวจหาเมื่อการตั้งค่าหน้าจอของฉันมีการเปลี่ยนแปลง เหตุการณ์ใหม่ screenschangeจะทําหน้าที่ดังกล่าว นั่นคือจะเริ่มทํางานเมื่อใดก็ตามที่มีการแก้ไขกลุ่มดาวบนหน้าจอ (โปรดทราบว่า "screens" เป็นพหูพจน์ในชื่อเหตุการณ์) ซึ่งหมายความว่าเหตุการณ์จะทริกเกอร์ทุกครั้งที่มีการเสียบหรือถอดหน้าจอใหม่หรือหน้าจอที่มีอยู่ (ไม่ว่าจะเสียบจริงหรือเสียบเสมือนในกรณีของ Sidecar)

คุณต้องค้นหารายละเอียดหน้าจอใหม่แบบไม่พร้อมกัน เนื่องจากเหตุการณ์ 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);
}

Polyfill

คุณไม่สามารถใช้ Polyfill สำหรับ Window Management API ได้ แต่สามารถใช้ Shim เพื่อ ปรับรูปร่างของ API เพื่อให้เขียนโค้ดกับ API ใหม่ได้โดยเฉพาะ

if (!('getScreenDetails' in window)) {
  // Returning a one-element array with the current screen,
  // noting that there might be more.
  window.getScreenDetails = as>ync () = [window.screen];
  // Set to `false`, noting that this might be a lie.
  window.screen.isExtended = false;
}

ส่วนอื่นๆ ของ API กล่าวคือ เหตุการณ์การเปลี่ยนแปลงหน้าจอต่างๆ และพร็อพเพอร์ตี้ screen ของ FullscreenOptions จะไม่ทริกเกอร์หรือถูกเบราว์เซอร์ที่ไม่รองรับ ละเว้นตามลำดับ

สาธิต

หากติดตามการพัฒนาของคริปโตเคอเรนซีต่างๆ อย่างใกล้ชิด คุณจะตรวจสอบตลาดได้จากเตียงนอนอย่างสะดวกสบายด้วยการตั้งค่าหน้าจอเดียวในแอปพลิเคชันของฉัน (ฉันไม่ต้องการอย่างยิ่ง เพราะฉันรักโลกใบนี้ แต่เพื่อประโยชน์ของบทความนี้ โปรดสมมติว่าฉันต้องการ)

หน้าจอทีวีขนาดใหญ่ที่ปลายเตียงซึ่งมองเห็นขาของนักเขียนบางส่วน บนหน้าจอมีโต๊ะซื้อขายสกุลเงินคริปโตปลอม
พักผ่อนและดูตลาด

เนื่องจากเป็นเรื่องเกี่ยวกับคริปโต ตลาดจึงอาจผันผวนได้ทุกเมื่อ หากเกิดกรณีนี้ขึ้น ฉันก็สามารถย้ายไปที่โต๊ะทำงานซึ่งมีจอภาพหลายจอได้อย่างรวดเร็ว ฉันคลิกหน้าต่างของสกุลเงินใดก็ได้และ ดูรายละเอียดทั้งหมดได้อย่างรวดเร็วในมุมมองแบบเต็มหน้าจอในหน้าจอตรงข้าม นี่คือรูปภาพล่าสุดของฉัน ที่ถ่ายในช่วงการแข่งขัน YCY สุดโหดครั้งล่าสุด มันทำให้ฉันเอามือปิดหน้าโดยไม่ทันตั้งตัว

ฉันที่ตื่นตระหนกเมื่อเห็นการเทขายหุ้น YCY

ลองใช้เดโมหรือดูซอร์สโค้ดใน GitHub

ความปลอดภัยและสิทธิ์

ทีม Chrome ได้ออกแบบและใช้ Window Management API โดยใช้หลักการหลักที่กำหนดไว้ในการควบคุมการเข้าถึงฟีเจอร์ที่มีประสิทธิภาพของแพลตฟอร์มเว็บ ซึ่งรวมถึงการควบคุมของผู้ใช้ ความโปร่งใส และการยศาสตร์ Window Management API จะแสดง ข้อมูลใหม่เกี่ยวกับหน้าจอที่เชื่อมต่อกับอุปกรณ์ ซึ่งจะเพิ่มพื้นผิวการลายนิ้วมือของผู้ใช้ โดยเฉพาะผู้ใช้ที่มีหลายหน้าจอที่เชื่อมต่อกับอุปกรณ์อย่างสม่ำเสมอ เพื่อลดความกังวลเรื่องความเป็นส่วนตัวนี้ เราจึงจำกัดพร็อพเพอร์ตี้ของหน้าจอที่เปิดเผยไว้ให้เหลือเพียงเท่าที่จำเป็นสำหรับกรณีการใช้งานการวางโฆษณาทั่วไป

เว็บไซต์ต้องได้รับสิทธิ์จากผู้ใช้เพื่อรับข้อมูลหลายหน้าจอ และวางหน้าต่างบนหน้าจออื่นๆ แม้ว่า Chromium จะแสดงป้ายกำกับหน้าจอแบบละเอียด แต่ เบราว์เซอร์ก็สามารถแสดงป้ายกำกับที่มีคำอธิบายน้อยกว่า (หรือแม้แต่ป้ายกำกับที่ว่างเปล่า) ได้

การควบคุมของผู้ใช้

ผู้ใช้จะควบคุมการเปิดเผยการตั้งค่าของตนเองได้อย่างเต็มที่ ผู้ใช้สามารถยอมรับหรือปฏิเสธข้อความแจ้งขอสิทธิ์ และเพิกถอนสิทธิ์ที่ให้ไว้ก่อนหน้านี้ผ่านฟีเจอร์ข้อมูลเว็บไซต์ในเบราว์เซอร์

การควบคุมระดับองค์กร

ผู้ใช้ Chrome Enterprise สามารถควบคุมหลายๆ ด้านของ Window Management API ได้ตามที่ระบุไว้ในส่วนที่เกี่ยวข้องของการตั้งค่ากลุ่มนโยบายแบบแยกส่วน

ความโปร่งใส

ข้อเท็จจริงที่ว่ามีการให้สิทธิ์ในการใช้ Window Management API หรือไม่จะ แสดงในข้อมูลเว็บไซต์ของเบราว์เซอร์ และยังสามารถสืบค้นได้ด้วย Permissions API

การคงอยู่ของสิทธิ์

เบราว์เซอร์จะคงการให้สิทธิ์ไว้ คุณเพิกถอนสิทธิ์ได้ผ่านข้อมูลเว็บไซต์ของเบราว์เซอร์

ความคิดเห็น

มีสิ่งใดเกี่ยวกับ API ที่ไม่ทำงานตามที่คุณคาดหวังไว้ไหม หรือมีเมธอด หรือพร็อพเพอร์ตี้ที่ขาดหายไปซึ่งคุณต้องใช้เพื่อนำแนวคิดไปใช้ไหม หากมีคำถามหรือความคิดเห็นเกี่ยวกับโมเดลความปลอดภัย

แสดงการสนับสนุน API

คุณวางแผนที่จะใช้ Window Management API ใช่ไหม การสนับสนุนแบบสาธารณะของคุณจะช่วยให้ทีม Chrome จัดลําดับความสําคัญของฟีเจอร์และแสดงให้ผู้ให้บริการเบราว์เซอร์รายอื่นๆ เห็นว่าการสนับสนุนฟีเจอร์เหล่านี้มีความสําคัญเพียงใด

  • แชร์วิธีที่คุณวางแผนจะใช้ในเธรด WICG Discourse
  • ทวีตถึง @ChromiumDev โดยใช้แฮชแท็ก #WindowManagement และ แจ้งให้เราทราบว่าคุณใช้ฟีเจอร์นี้ที่ใดและอย่างไร
  • ขอให้ผู้ให้บริการเบราว์เซอร์รายอื่นๆ ใช้ API

แหล่งข้อมูล

การรับทราบ

ข้อมูลจำเพาะของ Window Management API ได้รับการแก้ไขโดย Victor Costan Joshua Bell และ Mike Wasserman API นี้ได้รับการติดตั้งใช้งานโดย Mike Wasserman และ Adrienne Walker บทความนี้ได้รับการตรวจสอบโดย Joe Medley, François Beaufort และ Kayce Basques ขอขอบคุณ Laura Torrent Puig สำหรับรูปภาพ