背景
使用 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值传参为负数,
- 在自己项目中设置为负数也能实现居中效果
- 从而推测出原因
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。