背景
使用 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值傳參為負數,
- 在自己專案中設定為負數也能實現居中效果
- 從而推測出原因