最近收到个需求,需要将收费项目展示给用户看,肯定不能将系统工作台面向用户吧,所以只能将需要展示的数据传输到扩展屏中,给用户看。有点类似餐厅中前后屏的意思。
基本思路
- 浏览器打开一个页面
- 传输数据到另一个页面中
- 接收数据并展示
梳理功能
- chrome100+ 有新api, window.getScreenDetails() 可以获取当前系统的屏幕信息,当然获取之前需要请求权限:navigator.permissions.query({ name: 'window-management' }) 这也决定了只能谷歌浏览器 其他不行。其他浏览器因为找不到扩展屏的位置,只能在本窗口打开了。
如果满足条件,window.getScreenDetails()会返回下面的数据,我们可以找到isPrimary为false的屏幕,然后得到这块屏幕的位置。
screens: [{
availHeight: 816
availLeft: 0
availTop: 0
availWidth: 1536
colorDepth: 24
devicePixelRatio: 1.25
height: 864
isExtended: true
isInternal: true
isPrimary: true //是否是主屏幕
label: ""
left: 0
onchange: null
orientation: {angle: 0, type: 'landscape-primary', onchange: null}
pixelDepth: 24
top: 0
width: 1536
}]
- 打开页面 我们都知道有window.open(url, target, feature) MDN文档 我们常用的肯定是前两个参数,第三个参数就是打开的这个页面需要展示在哪个位置(left,top, width,height,这几个参数就是需要1中得到的扩展屏的信息)和页面的一些配置。
这个配置中有一个参数 “noopener ”,文档说加这个参数 新窗口会拿不到旧窗口的引用,属于安全机制,但是实测发现 旧窗口也拿不到新窗口的引用了。也就是无法使用window.postMessage进行通讯了。
如果不介意安全,可以去掉noopener 直接使用window.open()返回的窗口引用来通讯。 - 如果比较介意安全机制,就使用BroadcastChannel来通讯。这个api几乎现代浏览器都支持。
channel = new BroadcastChannel('pay-channel')
channel.postMessage({
//自定义对象
type: type,
data: data
})
- 新窗口设计
首先 url肯定也属于我们的项目页面,即使没有通过router.push打开,也需要将页面加入路由。
页面接收数据的方法,与旧窗口一样,必须保证'pay-channel',这个字符串要一样才可以通信
let channel = new BroadcastChannel('pay-channel')
channel.onmessage(message, (event) => {
//得到的数据展示在页面即可
}
- tips
在与新窗口通讯时,如果在新窗口刚打开 立马postMessage,新窗口会接收不到数据,因为页面还未初始化完成,所以需要延时,我实测至少需要延时1.5s
总结
经过上面的步骤 我们在谷歌浏览器已经实现了将窗口弹出到扩展屏的功能。