Chromium 新的彈窗機制以及 HTML 的 <dialog> 元素

justjavac發表於2017-06-27

自 1995 年 JavaScript 誕生之初,就包含了 3 個方法 alert()confirm()prompt()。在隨後的 Chrome 版本中,Chrome 團隊一直在修改原生彈窗的表現。

但是這種阻斷式的彈窗總被各種廣告網站惡意使用,因為只要彈窗出現,JavaScript 引擎就會一直等待,知道使用者操作。所以這種原生彈窗的最大用處不是用來提示使用者資訊,而是傷害使用者(Tech support scammers use subdomain trick to defeat blocking)

因此 Chromium 團隊強烈建議你不要使用這類彈窗。

而彈窗和 onbeforeunload 事件相結合之後那簡直就是大殺器,而此類彈窗經常被用來提示瀏覽者xxxx。

Chromium 團隊在 Chrome 51 中移除了對 onbeforeunload 彈窗的支援。在此之前 Safari 9.1 和 Firefox 4 早就已經移除了。當我們在 onbeforeunload 事件中呼叫 alert 時,會在 devtools 中產生警告:

Blocked alert('before unload') during beforeunload.複製程式碼

除此之外,alert()confirm()prompt() 的行為也做了改變,不再作為頂級的原生彈窗而存在,當彈窗所在的瀏覽器標籤被切走後,它們會自動消失。(Safari 9.1 說:“你怎麼到現在才來學啊!”)

Chromium 在官方部落格中說到:

對於 alert()/confirm()/prompt() 我們有很多替代的選擇。 譬如需要彈個通知訊息時(日曆應用)可以用Notifications API。 獲取使用者輸入可以用 HTML 中的 <dialog> 元素。 對於 XSS proofs-of-concept 則可用 console.log(document.origin)

<dialog> 作為 HTML 5.2 的元素,目前除了 Chrome 和 Opara 以外,其它瀏覽器均未支援。但是 Google 提供了一個 dialog-polyfill

一個最簡單的例子:

<dialog>This is da dialog!</dialog>複製程式碼

這段 html 什麼也不顯示,開發者需要使用 javascript 的 API .show().close() 來控制 dialog 的顯示和隱藏。

<dialog>
  <p>This is da dialog!</p>
  <button id="close">Close</button>
</dialog>

<button id="show">Open Dialog!</button>複製程式碼
var dialog = document.querySelector('dialog');

document.querySelector('#show').onclick = function() {
  dialog.show();
};

document.querySelector('#close').onclick = function() {
  dialog.close();
};複製程式碼

jsfiddle.net/m1dzstxo/

點選按鈕會出現一個彈窗(非常醜)

不過 dialog 作為一個 html 標籤,是可以使用 css 的。我們給它加一段 css 樣式:

dialog {
  border: 1px solid rgba(0, 0, 0, 0.3);
  border-radius: 6px;
  box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
}複製程式碼

jsfiddle.net/m1dzstxo/1/

再點選按鈕,彈窗了一個稍微漂亮點的彈窗:

我們還可以使用 .showModal() 彈窗一個模態對話方塊,當我們關閉彈窗時觸發 close 事件。我們還可以使用 ESC 鍵關閉一個彈窗,此時會觸發 cancel 事件。和其它所有事件一樣,我們可以通過呼叫 event.preventDefault() 來阻止預設行為。

直接彈窗一個模態視窗是不夠友好的,有時我們需要把背景虛化:

通過使用 CSS 的偽元素 ::backdrop 很容易就可以做到:

dialog::backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
}複製程式碼

為什麼使用 <dialog> 元素而不是第三方的 javascript 庫?

我覺得兩者並不衝突,目前大部分 javascript 庫都是使用 <div> 來模擬彈窗,當更多的瀏覽器開始支援 <dialog> 時,第三方的 javascript 庫也會考慮使用 <dialog> 作為首先的彈窗方式的,畢竟 <dialog> 是 HTML 5.2 規範中的。

相比 <div> 而言,<dialog> 更大強大,也更加符合規範。比如 <dialog> 的模態彈窗可以保證即使全屏的情況下,彈窗可以保持在最頂層(top-layer)。top-layer 定義在 whatwg 的 Fullscreen API 中,可以配合偽元素 ::backdrop 以及偽類 :fullscreen 一起使用。

開發面向未來的前端,當有 polyfill 方案時,我們應該總是使用最新標準。

相關文章