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

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

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

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

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

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

  • โปรแกรมตัดต่อกราฟิกแบบหลายหน้าต่าง à la 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
*/

เช่นเดียวกับคนส่วนใหญ่ที่ทำงานในแวดวงเทคโนโลยี ผมต้องปรับตัวให้เข้ากับการทำงานรูปแบบใหม่ และจัดตั้งสำนักงานที่บ้านส่วนตัว ภาพของฉันเหมือนกับภาพด้านล่าง (หากสนใจ ก็อ่านรายละเอียดทั้งหมดเกี่ยวกับการตั้งค่าของฉันได้) iPad ที่อยู่ถัดจาก MacBook ของฉันเชื่อมต่อกับแล็ปท็อปผ่านไฟล์ช่วยเหลือ ฉันจึงสามารถเปลี่ยน 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

ฉันจะเข้าถึงพร็อพเพอร์ตี้ 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" ทำหน้าที่นี้ทุกประการ กล่าวคือ เหตุการณ์จะเริ่มทํางานทุกครั้งที่มีการแก้ไขกลุ่มภาพ (โปรดสังเกตว่า "หน้าจอ" เป็นพหูพจน์ในชื่อเหตุการณ์) ซึ่งหมายความว่าเหตุการณ์จะเริ่มทํางานเมื่อหน้าจอใหม่หรือหน้าจอที่มีอยู่ (ทั้งในโหมดทางกายภาพหรือเสมือนในกรณีของ 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 ครั้งล่าสุด มันติดฉันมากเลย แล้วก็ปล่อยฉันไว้ เอามือปิดหน้า

ผู้เขียนถือสีหน้าตื่นตระหนกและจ้องไปที่โต๊ะซื้อขายสกุลเงินคริปโตปลอม
การพบความตื่นตระหนกจากการแช่เลือดใน 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 อย่าลืมใส่รายละเอียดให้มากที่สุดเท่าที่จะทำได้ อธิบายวิธีการง่ายๆ สำหรับการทำซ้ำ และป้อน Blink>Screen>MultiScreen ในช่องคอมโพเนนต์ Glitch เหมาะสำหรับการแชร์การดำเนินการซ้ำที่ง่ายและรวดเร็ว

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

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

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

ลิงก์ที่มีประโยชน์

ข้อความแสดงการยอมรับ

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