[譯]迎接新的 Dialog 元素

Fate_輕舞飛揚發表於2019-02-27

迎接新的 Dialog 元素

用字母在前面裝飾的舊鐵郵箱

HTML 5.2 為原生彈窗對話方塊引入了一個新的 <dialog> 元素。 乍一看,它似乎相當簡單(本來就是),但當我和它打交道的過程中,我發現有一些很棒的新特性很容易被忽視掉。

在本文的最後我加上了一個完整可行的 Demo ,但是如果你想在閱讀的過程中也檢視的話,你可以看這裡.

這是一個基本的彈窗對話方塊標記:

<dialog open>
  Native dialog box!
</dialog>
複製程式碼

open 屬性意味著對話方塊是可見的。沒有它,除非你用 JavaSript 使它出現,否則它就是隱藏的。在新增樣式之前,對話方塊渲染如下所示:

對話方塊中的文字有加粗的黑色輪廓

它在頁面中是絕對定位的,因此它會按照你所期望的那樣出現在其他內容前面,並且水平居中。預設情況下,它和內容等寬。

基本操作

JavaScript 有幾個方法和屬性可以方便地處理 <dialog> 元素。你可能最需要的兩個方法是 showModal()close()

const modal = document.querySelector(`dialog`);

// 使對話方塊出現(新增 `open` 屬性)
modal.showModal();

// 隱藏對話方塊(移除 `open` 屬性)
modal.close();
複製程式碼

當你用 showModal() 開啟對話方塊的時候,頁面會新增一層背景,阻止使用者與對話方塊之外的內容互動。預設情況下,這層背景是完全透明的,但是你可以改變 CSS 屬性使它可見(後面會有更多介紹)。

按 Esc 鍵會關閉對話方塊,你也可以提供一個關閉按鈕來觸發 close() 方法。

還有第三個方法,show() 也會讓對話方塊出現,但不會伴隨背景層。使用者仍可以和對話方塊之外的可見的元素進行互動。

瀏覽器支援和 Polyfill

現在,只有 Chrome 支援 <dialog> 。Firefox 提供了預設樣式,但是 JavaScript API 僅在標誌後啟用。我猜想 Firefox 會很快支援它。

慶幸地是,polyfill 提供了 JavaScript 事件和預設樣式。用 npm 安裝 dialog-polyfill 來使用它 —— 或者使用常用的舊的 <script> 標籤。這樣 <dialog> 就可以在 IE9及以上版本中使用了。

當使用 polyfill 時,頁面上的每個對話方塊都需要被初始化:

dialogPolyfill.registerDialog(modal);
複製程式碼

這不會替代擁有它的瀏覽器中的原生事件。

樣式

開啟和關閉對話方塊完成了,但是它起初看起來並不專業。我們像給其他元素新增樣式那樣,給對話方塊新增樣式。背景層可以用新的 ::backdrop 偽元素來設計。

dialog {
  padding: 0;
  border: 0;
  border-radius: 0.6rem;
  box-shadow: 0 0 1em black;
}

dialog::backdrop {
  /* make the backdrop a semi-transparent black */
  background-color: rgba(0, 0, 0, 0.4);
}
複製程式碼

對於那些需要使用 polyfill 的老瀏覽器,這個偽元素選擇器將不會起作用,然而,在這個對話方塊位置後,polyfill 會立即新增一個 .backdrop 元素。你可以像這樣用 CSS 來定位它:

dialog + .backdrop {
  background-color: rgba(0, 0, 0, 0.4);
}
複製程式碼

新增更多的標記來提供樣式的鉤子。一個常用的做法是將對話方塊劃分為標題,正文和頁尾:

<dialog id="demo-modal">
  <h3 class="modal-header">A native modal dialog box</h3>
  <div class="modal-body">
    <p>Finally, HTML has a native dialog box element! This is fantastic.</p>
    <p>And a polyfill makes this usable today.</p>
  </div>
  <footer class="modal-footer">
    <button id="close" type="button">close</button>
  </footer>
</dialog>
複製程式碼

給它新增一些 CSS ,你可以讓對話方塊做成任何你想要的外觀:

更多控制

通常,我們想要從對話方塊中獲得更多使用者反饋。當關閉對話方塊時,你可以傳遞一個字串值到 close() 方法。該值將會被賦值給對話方塊 DOM 元素的 retrunValue屬性,因此它可以在後面被讀取到:

modal.close(`Accepted`);

console.log(modal.returnValue); // logs `Accepted`
複製程式碼

還有一些事件你可以監聽。兩個有用的事件是 close (當對話方塊關閉的時候觸發)和 cancel (當使用者按了 Esc 關閉對話方塊時觸發)。

有一件事似乎被忘掉了,當背景層被點選時能夠關閉對話方塊,但有一個變通方案。當點選背景層時,觸發 <dialog> 的點選事件作為事件目標。並且,如果你構造對話方塊使得子元素填充了整個對話方塊,那些子元素將會被作為對話方塊內任何點選的目標。這種方式,你可以監聽對話方塊上的點選,當點選事件的目標是對話方塊本身的時候關閉它:

modal.addEventListener(`click`, (event) => {
  if (event.target === modal) {
    modal.close(`cancelled`);
  }
});
複製程式碼

雖然不完美,但是起了作用。如果你找到了更好的方法來檢測背景層上的點選,請讓我知道。

完整可行的 Demo

我在下面的示例中演示了很多東西。親自實踐下,看你還能用 <dialog> 做些什麼。它包含了 polyfill,所以它應該能在大多數瀏覽器中執行。

請參閱 Keith J. Grant (@keithjgrant) 在 CodePen 上的


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章