你的屏幕管理助手-Window Management API

652 阅读5分钟

大家好,我是CC,在这里欢迎大家的到来~

场景

我们在开发工作中经常会使用多个屏幕,多屏操作更加方便快捷;那知道如何在浏览器里进行多屏幕的管理呢?

使用 Web API 的 Window Management API。虽然目前它的兼容性还不是很全,但是未来可期,而且它得使用场景颇为广泛。

  1. 假如我是一个投资者,每天需要面对很多屏幕来浏览股市涨跌。

  1. 假如我是一个保安,保卫一方平安,每天要盯着监控录像。

下面进入正文,我们来试试 Window Management API 的效果。

屏幕权限

浏览器安全策略的缘故,当我们想使用浏览器提供的一些 API 时,需要手动授权。

我们现在需要获取的是 window-management 的使用权限。

const permission = await queryWindowManagement();

async function queryWindowManagement() {
  // https://developer.mozilla.org/zh-CN/docs/Web/API/Permissions/query
  return await navigator.permissions.query({ name: 'window-management' });;
}

if (permission.state === "granted") { // 已经授权
  // 执行下一步
} else if (permission.state === "prompt") { // 询问是否授权
  // 请求授权
} else if (permission.state === "denied") {
  // 权限被拒绝
}

询问是否授权这里目前有一个坑:

有的Web API 自身有请求权限的方法,比如 Notifications API 有方法 requesePermission() ;但是有的没有,比如 Geolocation API。恰巧 Window Management API 也没,悲催

但是 Permissions API 未来会提供统一的请求权限的方法 Permissions.request() 和 Permissions.requestAll() ,截止文章发布时间这两个方法未有浏览器实现

所以这里我们只能手动去更改浏览器的权限。

屏幕信息

在获取到屏幕权限后,我们就可以查看屏幕的详细信息了。

但是在这之前,我们需要了解一个概念——多屏原点。

多屏原点

多屏原点——通俗来讲,就是把我们的屏幕放到一个直角坐标系里,原点O(0,0)点就是我们的多屏原点。那哪个位置是原点呢?

我们使用 MDN的例子:1920 x 1080 扩展屏设置为主显示器,1440 x 900 电脑显示器设置为辅助显示器,操作系统 UI 在屏幕顶部占用 25px。

  1. 当辅助屏幕位于主屏幕右侧,多屏原点就是主显示器的左上角,坐标(0,0)

  1. 当辅助屏幕位于主屏幕左侧,多屏原点也是主显示器的左上角,坐标(0,0)

ScreenDetailed

继承 Screen 对象,用户可用屏幕设备的属性

  • label 屏幕名称
  • isPrimary 是否是主屏幕
  • isInternal 是电脑自带屏还是外接屏
  • top 相对多幕原点顶部距离
  • left 相对多幕原点的横向距离
  • availTop 可用屏幕区域相对多屏原点的 y 坐标
  • availLeft 可用屏幕区域相对多屏原点的 x 坐标
  • devicePixelRatio 设备像素比
  • isExtended 是否有多个屏幕

Screen

  • width 屏宽
  • height 屏高
  • availWidth 浏览器最大宽度
  • availHeight 浏览器最大高度
  • pixelDepth 位深度/色彩深度
  • colorDepth 颜色深度
  • orientation 屏幕当前方向

以上属性我们在哪里能看到呢?通过 window.getScreenDetails() 方法返回一个 ScreenDetails 对象,包含 currentScreen 当前屏幕的属性和 screens 所有可用屏幕的属性。

let screens = [];
let currentScreen = null;
let screenDetails = null;

screenDetails = await window.getScreenDetails();
currentScreen = screenDetails.currentScreen;
screens.push(...screenDetails.screens);

投送屏幕

屏幕投送就是把某个内容的浏览器放到某个屏幕上。

有两种方式:

一是通过在某个坐标点打开新的浏览器窗口或者标签页,二者可以把当前浏览器移动到屏幕上。

打开

function delivery (screen, url) {
  const {top, left, width, height} = screen;
  const features = [
    `left=${left}`,
    `top=${top}`,
    `width=${width}`,
    `height=${height}`,
    `menubar=no`,
    `toolbar=no`,
    `location=no`,
    `status=no`,
    `resizable=yes`,
    `scrollbars=no`
  ].join(",");
  return window.open(url, Math.random().toString(), features);
}

注意:在 Mac 笔记本上如果当前浏览器处于全屏状态,window.open 会打开一个标签页,而如果当前浏览器未处于全屏状态下的话 window.open 会重新打开新的浏览器窗口。

移动

function move(top, left) {
  window.moveTo(top, left);
}

全屏

屏幕全屏可以控制把某个 DOM 全屏以及全屏放置到哪个屏幕上。

async function toggleFullscreen(screenId) {
  await toggleElementFullscreen(document.body, screenId);
}

async function toggleElementFullscreen(element, screenId) {
  if (Number.isInteger(screenId) && screenId >= 0 && screenId < screens.length) {
    // 选择在对应屏幕上全屏展示
    await element.requestFullscreen({ screen: screens[screenId] });
  } else if (document.fullscreenElement == element) {
    // 如果已经全屏则退出全屏
    await document.exitFullscreen();
  } else {
    // 默认在当前屏幕全屏
    await element.requestFullscreen();
  }
}

监听屏幕变化

change()

change 事件是 Screen 对象上的,只有 Screen 上一个或多个属性发生改变时就会触发特定屏幕上的 change 事件。

const firstScreen = (await window.getScreenDetails()).screens[0];

firstScreen.addEventListener("change", (event) => {
  console.log("The first screen has changed.", event, firstScreen);
});

currentscreenchange()

currentscreenchange 事件属于 ScreenDetails 对象,触发事件的行为有以下几个:

  1. 当前浏览器窗口被移动到其他屏幕上

  2. Screen 对象的一个或多个属性值发生变化

  3. ScreenDetails 对象的以下一个或多个属性值发生变化

    • isPrimary
    • isInternal
    • top
    • left
    • availTop
    • availLeft
    • devicePixelRatio
const screenDetails = await window.getScreenDetails();

screenDetails.addEventListener("currentscreenchange", (event) => {
  const details = screenDetails.currentScreen;
  console.log("The current screen has changed.", event, details);
});

screenchange()

screenchange 事件也属于 ScreenDetails 对象,当系统可用的屏幕集发生变化时,像有新屏幕可用或现有屏幕不可用,比如拔掉扩展屏的 HDMI 连线就是现有屏幕不可用。

当触发 screenchange 事件时,我们就能监测到什么时候可用屏幕发生了更改,然后上报更改,关闭所有的浏览器窗口,最后重新打开所有窗口来适应新的屏幕配置。

const screenDetails = await window.getScreenDetails();

let noOfScreens = screenDetails.screens.length;

screenDetails.addEventListener("screenschange", () => {
  if (screenDetails.screens.length !== noOfScreens) {
    console.log(
      `The screen count changed from ${noOfScreens} to ${screenDetails.screens.length}`,
    );
    noOfScreens = screenDetails.screens.length;
  }

  updateWindows();
});

更多有趣的 Demo

  1. 多窗口的代码学习环境
  2. 多窗口游戏
  3. 交易平台
  4. 功能性 Demo

参考资料

developer.mozilla.org/en-US/docs/…

developer.mozilla.org/en-US/docs/…

API 兼容性目前还需要再等等!