背景
使用 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值傳參爲負數,
- 在自己項目中設置爲負數也能實現居中效果
- 從而推測出原因
感謝閱讀,祝好