背景
使用 window.open 进行弹窗显示,实现微信二维码弹窗功能在双屏情况下,chrome 浏览器位于副屏弹窗时,会存在弹窗位置异常问题。目前网上相关解析及解决方案几乎没有,故写此文章以作分享。
文章重点
双屏情况下,chrome 浏览器弹窗位置问题
多屏幕时,chrome 浏览器位于非主屏进行弹窗显示时,设置弹窗的 left,top 将会异常
本文将分析其显示异常的原因,并给出解决方案
解决该问题的分析过程
这是本文分享的另一个重点
除了解决方案,希望能通过本文和大家分享笔者解决该问题时的思路和方法。
这些方法可能不是最优的,但希望能给大家带来一点触动或者启示。在解决到其他问题的时候也用得上。
window.open 的第三个参数及其兼容性介绍
window.open 方法相信大家都不会陌生,通常用于传递一个地址参数,新建一个浏览器 tab 页面。
但除了第一个地址参数,window.open 还另外接收两个参数,分别是「strWindowName(新窗口的名称)」,「strWindowFeatures(新窗口特性)」
这强调的是第三个参数,当设置了第三个参数后,新开的弹窗将会在原页面的基础上,已非 tab 页面的形式进行显示,有以下几个特点
在原页面上进行弹窗显示,而不是新起浏览器 tab 页面进行跳转。其显示方式类似 alert 弹窗,属于原页面的一个功能模块,而不是跳转至新页面。
非 tab 页面,这意味着它不像其他 tab 页面那样可以放在浏览器 tab 栏中,它是折叠不进去了,是以弹窗的形式呈现。
第三个参数「strWindowFeatures」可以设置新窗口特性,例如宽度,高度,距顶,距左,是否显示滚动条等等。本文不做详细介绍,参数详情可以参考这篇文章
需要注意的是,strWindowFeatures 里的特效并不是每个浏览器都支持的,不同于「dom」,这属于「bom(borwser Object Model)」的内容。具体兼容性这里也不讲了,网上也有相关文章
chrome 的兼容性与坑(重点一)
异常的显示
即使看完上面的兼容性文章,当你使用 chrome 浏览器,位于非主屏进行弹窗时,依然会存在位置设置异常的问题。
实现居中显示弹窗,一般代码会这样写
const windowWidth = window.screen.width // 屏幕宽度
const windowHeight = window.screen.height // 屏幕高度
const pageWidth = 600 // 弹出窗口的宽度
const pageHeight = 550 // 弹出窗口的高度
let pageTop = (windowHeight – pageHeight) / 2 // 窗口的垂直位置
let pageLeft = (windowWidth – pageWidth) / 2 // 窗口的水平位置;
window.open(‘xxx’, ‘xxx’, `width=${pageWidth},height=${pageHeight},top=${pageTop},left=${pageLeft}`) // 实现居中弹窗
这段代码在主屏幕显示没有问题,可以居中显示,但如果将页面移换到副屏幕进行弹窗时。你会发现,无论参数怎么设置,弹窗都会在屏幕最左侧或屏幕最右侧进行显示,并不是水平居中。点击这里查看示例
异常的原因及其解决方案
原因可能很多同学都难以想到,这是因为弹窗的 left 和 top 参数,并不是基于当前页面作为原点进行计算的,而是以主屏幕作为原点进行计算
所以进行位置设置时,需要计算其基于主屏幕的偏移值。
那怎么知道当前是否处于主屏幕上呢?可以通过 window.screen.availLeft 参数来解决,该参数返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。
通过该参数,甚至不需要知道目前处于哪个屏幕上,直接加上该参数即可基于当前屏幕进行定位。修改后的代码如下
const {
availLeft, // 返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。
availHeight, // 浏览器在显示屏上的可用高度,即当前屏幕高度
availWidth, // 浏览器在显示屏上的可用宽度,即当前屏幕宽度
} = window.screen
const pageWidth = 600 // 弹出窗口的宽度
const pageHeight = 550 // 弹出窗口的高度
let pageTop = (availHeight – pageHeight) / 2 // 窗口的垂直位置
let pageLeft = (availWidth – pageWidth) / 2 // 窗口的水平位置;
left += availLeft // 加上屏幕偏移值
window.open(‘xxx’, ‘xxx’, `width=${pageWidth},height=${pageHeight},top=${pageTop},left=${pageLeft}`) // 实现居中弹窗
「top」参数的设置同样存在这个问题
如果主屏幕和副屏幕并不是处于相同的高度,「top」值的设置同样会由于距系统主屏幕定位,而发生定位异常的显示。看下面这张图可能更好地理解
另外目前笔者发现,这个兼容性问题,仅会在 chrome 内核的浏览器存在,safari 上运行是不存在该问题的。综上所述,得出最终的解决方案为
const {
availTop, // 返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。
availLeft, // 返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。
availHeight, // 浏览器在显示屏上的可用高度,即当前屏幕高度
availWidth, // 浏览器在显示屏上的可用宽度,即当前屏幕宽度
} = window.screen
const pageWidth = 600 // 弹出窗口的宽度
const pageHeight = 550 // 弹出窗口的高度
let pageTop = (availHeight – pageHeight) / 2 // 窗口的垂直位置
let pageLeft = (availWidth – pageWidth) / 2 // 窗口的水平位置;
if (navigator.userAgent.indexOf(‘Chrome’) !== -1) {// 兼容 chrome 的 bug
top += availTop // 距顶偏移值
left += availLeft // 距左偏移值
}
window.open(‘xxx’, ‘xxx’, `width=${pageWidth},height=${pageHeight},top=${pageTop},left=${pageLeft}`) // 实现居中弹窗
问题解决过程(重点二)
笔者遇到该问题是通过如下方式一一寻找解决方案
百度
最基础,成本最低的一步,笔者进行过以下关键字的搜索(这里主要突出关键字提取)
window.open 居中显示
window.open left chrome
window.open left 异常
window.open 定位 异常
window.open chrome 兼容性
window.open 双屏显示异常
搜索结果,找到了相关的问题,但未能找到真正有效的解决方案。
问答论坛
stackoverflow,国外著名的编程问答网站,纯英文,内容全。
segmentfault,国内的 stackoverflow,内容也不错。
MDN 官网
维基百科:MDN Web Docs(旧称 Mozilla Developer Network、Mozilla Developer Center,简称 MDN)是一个汇集众多 Mozilla 基金会产品和网络技术开发文档的免费网站。
一般可以看作前端基础函数的官方说明文档,具有一定的权威性,当然一定程度上会更为难懂
其他页面代码分析
寻找网上实现了该功能的网站,下载其页面代码进行分析。网上的代码都是加密过的,虽然不直观,但能推测或猜出一些端倪
各关键词搜索
首先,通过 chrome 调试工具,找到触发弹窗的按钮
ctrl+s,下载整个页面,
通过 IDE 全局搜索整个页面中关于该按钮的信息,如 class,id,及其他属性值,能定位到该按钮的属性都全局搜索一遍
逐文件查看,有无相关配置
window.open 函数名搜索
打开弹窗肯定需要通过该语句,全局搜索,如果 window 没被覆盖的话应该能找到
第三个参数搜索
根据 strWindowFeatures 可配置项目进行全局搜索,
提取其特点,如「scrollbars」,「titlebar」这些变量
以及其字符串形式传参的特点,搜索「,left=」「,height=」
重置函数
终极大招,函数重置,及通过在 chrome 控制台重置该函数,来观察其传参情况
打开 chrome 控制台,找到 Console 栏,拷贝如下代码
window.open = function () {
console.log(arguments)
}
再此进行登录弹窗操作,触发函数执行
笔者是在前三个方法都失败的情况下,通过第四个方法找到的问题所在。
发现其 left 值传参为负数,
在自己项目中设置为负数也能实现居中效果
从而推测出原因
感谢阅读,祝好