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

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

API การจัดการหน้าต่าง

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

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

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

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

วิธีใช้ Window Management API

ปัญหา

น่าเสียดายที่Window.open() ซึ่งเป็นแนวทางที่ผ่านการทดสอบมาอย่างยาวนานในการควบคุมหน้าต่าง ไม่ทราบว่ามีหน้าจอเพิ่มเติม แม้ว่าบางแง่มุมของ API นี้จะดูล้าสมัยไปหน่อย เช่น พารามิเตอร์ windowFeatures DOMString แต่เราก็ใช้ API นี้มาอย่างยาวนาน หากต้องการระบุตําแหน่งของหน้าต่าง ให้ส่งพิกัดเป็น 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
*/

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

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

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

popup.moveTo(2500, 50);

นี่คือการคาดเดาคร่าวๆ เนื่องจากไม่มีวิธีที่จะทราบขนาดของหน้าจอที่ 2 ข้อมูลจาก window.screen จะครอบคลุมเฉพาะหน้าจอในตัวเท่านั้น แต่ไม่ครอบคลุมหน้าจอ iPad width ที่รายงานของหน้าจอในตัวคือ 1680 พิกเซล ดังนั้นการเปลี่ยนเป็น 2500 พิกเซลอาจช่วยในการเลื่อนหน้าต่างไปยัง iPad ได้ เนื่องจากฉันทราบมาว่า 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

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

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

getScreenDetails()

เมื่อรู้ว่าการตั้งค่าปัจจุบันสำหรับหลายหน้าจอแล้ว ฉันจึงดูข้อมูลเพิ่มเติมเกี่ยวกับหน้าจอที่ 2 ได้โดยใช้ Window.getScreenDetails() การเรียกใช้ฟังก์ชันนี้จะแสดงข้อความแจ้งสิทธิ์ที่ถามว่าเว็บไซต์สามารถเปิดและวางหน้าต่างบนหน้าจอได้ไหม ฟังก์ชันดังกล่าวจะแสดงผลสัญญาที่แก้ไขด้วยออบเจ็กต์ 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 จะทําเช่นนั้นทุกประการ โดยจะทริกเกอร์เมื่อใดก็ตามที่มีการแก้ไขกลุ่มดาวของหน้าจอ (โปรดสังเกตว่า "Screen" เป็นพหูพจน์ในชื่อเหตุการณ์) ซึ่งหมายความว่าเหตุการณ์จะเริ่มต้นทุกครั้งที่เสียบหรือถอดปลั๊กหน้าจอใหม่หรือหน้าจอที่มีอยู่ (จริงหรือเสมือนในกรณีของ 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);
}

โพลีฟิลล์

คุณไม่สามารถโพลีฟิล 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 เช่น เหตุการณ์การเปลี่ยนแปลงหน้าจอต่างๆ และพร็อพเพอร์ตี้ screen ของ FullscreenOptions จะไม่ทํางานหรือถูกละเว้นโดยเบราว์เซอร์ที่ไม่รองรับ

สาธิต

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

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

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

ผู้เขียนใช้มือจับหน้าตื่นตระหนกซึ่งจ้องมองไปที่โต๊ะซื้อขายสกุลเงินคริปโตปลอม
Panicky, witnessing the YCY bloodbath.

คุณอาจเล่นกับการสาธิตที่ฝังอยู่ด้านล่าง หรือดูซอร์สโค้ดในข้อบกพร่องก็ได้

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

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

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

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

การควบคุมขององค์กร

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

ความโปร่งใส

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

การเก็บรักษาสิทธิ์

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

ความคิดเห็น

ทีม Chrome อยากทราบความคิดเห็นของคุณเกี่ยวกับ Window Management API

บอกเราเกี่ยวกับการออกแบบ API

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

  • แจ้งปัญหาเกี่ยวกับข้อกำหนดใน GitHub repo ที่เกี่ยวข้อง หรือแสดงความคิดเห็นในปัญหาที่มีอยู่

รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน

คุณพบข้อบกพร่องในการติดตั้งใช้งาน Chrome ไหม หรือการติดตั้งใช้งานแตกต่างจากข้อกําหนดหรือไม่

  • รายงานข้อบกพร่องที่ new.crbug.com โปรดระบุรายละเอียดให้มากที่สุด วิธีการง่ายๆ ในการจำลองข้อบกพร่อง และป้อน Blink>Screen>MultiScreen ในช่องคอมโพเนนต์ Glitch เหมาะอย่างยิ่งสำหรับการแชร์การจำลองข้อบกพร่องที่รวดเร็วและง่ายดาย

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

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

  • แชร์ว่าคุณวางแผนจะใช้ WICG อย่างไรในชุดข้อความ Discourse ของ WICG
  • ส่งทวีตถึง @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 สำหรับรูปภาพ