1

js实现多屏/跨屏窗口放置

 2 years ago
source link: https://blog.p2hp.com/archives/8923
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

js实现多屏/跨屏窗口放置 | Lenix Blog

目前有越来越多的开发者外接多个显示器进行工作,但是有没有发现你在浏览器中打开新窗口时,都只会显示在你当前的显示屏里,如果想放置在某个浏览器中,需要把窗口拖过去,有没有可能直接在指定的显示屏中打开窗口呢?

通常我们可以通过 window.open 方式来打开一个窗口,如:

const popup = window.open(
  "https://www.baidu.com/",
  "_blank",
  "width=400, height=300, left=100, top=100"
);

但是都只是在当前屏幕上打开的,如何能让其在指定的显示屏中打开窗口呢?

Multi-Screen Window Placement API

从Chrome 86起,开始支持Multi-Screen Window Placement API了,不过还处于试验阶段,可以在 chrome://flags 里开启 #enable-experimental-web-platform-features

 判断浏览器是否支持该特性

if ("getScreens" in window) {
  //支持
}

判断是否接入多个显示屏

await isMultiScreen()

请求权限

const permission = await navigator.permissions.query({
    name: 'window-placement'
});

getScreens()方法

await window.getScreens();

事件监听

window.addEventListener('screenschange', () => {
    //
});

全屏

requestFullscreen也相应增加了screen配置项

***.requestFullscreen({
    screen: screen[0]
})

演示效果

下面视频演示分别点击页面上的3个按钮,会分别在对应的显示屏中打开一个小窗口。

代码示例

css、html

<style>
#demo{width: 600px;}
#demo .warning {font-size: 14px; color: #f00}
#demo .buttons input[type="button"] {height: 40px; font-size: 15px; margin-right: 20px; color: #fff; background: #389e88; border: 0; border-radius: 5px;}
#demo .buttons input[type="button"]:active {background: rgb(10, 233, 10)}
#demo .screens {margin-top: 10px}
#demo .screens dl {background: #ccc; font-size: 13px; line-height: 20px; margin-top: 10px; padding: 10px}
#demo .screens dt {font-size: 16px; font-weight: bold; color: #1d3bd2; margin-bottom: 10px}
#demo .screens dd {padding: 0; margin: 0;}
</style>


<div id="demo">
    <strong class="warning"></strong>
    <div class="buttons"></div>
    <div class="screens"></div>
</div>

js

class MultiScreen {
    constructor() {
        const _this = this;
        _this.screens = [];
        _this.init();
    }
    async init() {
        const _this = this;
        if (!('getScreens' in self)) {
            alert('你的chrome版本不支持该功能!');
        } else if ('isMultiScreen' in self && !(await isMultiScreen())) {
            alert('请接入多个显示屏查看该demo!');
        } else {
            const permission = await navigator.permissions.query({
                name: 'window-placement'
            });
            permission.addEventListener('change', () => {
                _this.updateScreensInfo();
            });
            if ('onscreenschange' in self) {
                window.addEventListener('screenschange', () => {
                    _this.updateScreensInfo();
                });
                _this.updateScreensInfo();
            }
        }
    }
    async getScreensData() {
        const _this = this;
        _this.screens = (await getScreens().catch(_ => {})) || [window.screen];
    }
    async updateScreensInfo() {
        const _this = this;
        let buttons = [];
        let screens = [];


        await _this.getScreensData();


        const permission = await navigator.permissions.query({
            name: 'window-placement'
        });


        if (permission.state === 'denied') {
            document.querySelector('#demo .warning').innerHTML = '您禁用了窗口放置权限,请开启使用';
        }


        _this.screens.forEach((item, index) => {
            buttons.push(`
                <input type="button" value="在第 ${index + 1} 个显示屏中打开" data-index="${index + 1}">
            `);
            screens.push(`
                <dl>
                    <dt>screen ${index + 1} :</dt>
                    <dd>
                        id: ${item.id}<br>
                        width: ${item.width}<br>
                        height: ${item.height}<br>
                        availWidth: ${item.availWidth}<br>
                        availHeight: ${item.availHeight}<br>
                        left: ${item.left}<br>
                        top: ${item.top}<br>
                        primary: ${item.primary}<br>
                        internal: ${item.internal}<br>
                        touchSupport: ${item.touchSupport}<br>
                    </dd>
                </dl>
            `);
        });
        document.querySelector('#demo .buttons').innerHTML = buttons.join('');
        document.querySelector('#demo .screens').innerHTML = screens.join('');
        document.querySelectorAll('#demo input[type="button"]').forEach((item, index) => {
            item.addEventListener('click', () => _this.openWin(index, screens[index]));
        });
    }
    openWin(index, html) {
        const _this = this;
        const screen = _this.screens[index];
        const optionsStr = `
            width=400,
            height=300,
            left=${screen.availLeft + (screen.availWidth / 2) - 200},
            top=${screen.availTop + (screen.availHeight / 2) - 150}
        `;
        const win = window.open('about:blank', '_blank', optionsStr);
        win.document.write(html);
    }
}
new MultiScreen();

screen数据

以下是部分screen数据:

其中 primary 表示是否是主显示屏,internal 表示是否是内置显示屏。

id: 0
width: 1280
height: 800
availWidth: 1280
availHeight: 734
left: 0
top: 0
primary: true
internal: true
touchSupport: false
id: 1
width: 1920
height: 1200
availWidth: 1920
availHeight: 1177
left: 0
top: -1200
primary: false
internal: false
touchSupport: false

应用场景

可能有人会觉得这个功能意义不大,但是我觉得一方面可以提升交互体验,另一方面,随着多屏、折叠屏等设备越来越多,跨屏交互势必会被重视,(如折叠屏就已经有了相关css与js api: @media (spanning: single-fold-vertical), window.getWindowSegments()),可以提前掌握并进行一些技术创新。

目前我能想到的几个应用场景:

1、股市行情展示

同时在多个屏幕上打开并排列不同的股市行情窗口。

2、数据可视化大屏展示

目前的数据可视化大屏展示基本都是整合在一个页面中的,如果需要调整结构布局,可能就需要修改代码,如果开发时考虑好让每个模块可以独立展示,那么就可以借助这个功能,设定好布局后,就可以一键窗口排列展示。

3、在线ppt演示

目前市场上有很多在线版的ppt,提供了演讲者模式,一个窗口是用来在投影仪上展示的,另一个是用来在笔记本屏幕上显示演讲者笔记,但是目前使用时就需要手动去调整窗口到不同的屏幕上,现在我们是否可以这样去优化提升体验,点击 “演讲者模式” 按钮后,直接一个窗口全屏展示在投影仪,另一个演讲者笔记窗口保留在笔记本屏幕上。

4、简单的小游戏多屏布局

一点设想

目前要在不同屏幕上打开窗口,主要还是通过 js 的window.open去实现,以后能不能直接在 <a> 标签的_target上增加一项呢,指定在哪个显示屏上打开,如:

<a href="https://www.so.com/" _target="screen[0]">...</a>

以及 window.open 第二个参数是不是也可以考虑支持呢?

Chrome扩展

在此顺便推广一下我以前开发的一个chrome扩展 “多显示窗口管理” :

详细介绍见另一个文章:Chrome插件分享:多显示器窗口管理

该扩展支持在多个显示器之间进行窗口切换、最大化、居中、贴边、垂直/水平排列、标签页从窗口分离/合并、以及快捷键支持。

1. 窗口可以在多个显示器之间快速移动,而无需拖动;

2. 窗口最大化、居中、贴边;

3. 窗口1x2、2x1、2x2排列;

4. 窗口标签页从窗口分离、合并;

默认支持以下快捷键:

1. 在多个显示器之间切换(windows: ctrl+→,Mac: ⌘+→)

2. 调整窗口大小且循环切换(windows: ctrl+↑,Mac: ⌘+↑)

3. 窗口依次在屏幕左、上、右、下贴边切换(windows: ctrl+←,Mac: ⌘+←)

其他快捷键可自定义设置。

61be759fb69648c46c41a7fc452ec6ff.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK