chrome彈窗在雙屏情況下left居中定位異常分析

背景

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

感謝閱讀,祝好

圖片

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章