LiveView 0.18 發布
Chris McCord 於 2022 年 9 月 21 日張貼
我們一直在為 LiveView 0.18.0 開發一些改變遊戲規則的功能。聲明式分配和插槽提供編譯時期警告和增強文件,讓建置您自己的 UI 或使用 UI 程式庫成為一種愉快的體驗。這些新功能將函式元件提升到另一個層次,提供真正一流的可組成元件系統。
此外,新的開箱即用對焦元件和 JS 指令提供無障礙改善,確保 LiveView 應用程式對所有使用者都能良好運作。我們還發布了一個新的 mix 格式器外掛程式,用於格式化 HEEx 範本,這是您在使用過後就無法割捨的功能。
要了解為什麼這些功能如此重要,讓我們來看看一個簡單的函式元件。比方說我們在應用程式中有一個 modal
元件,我們想要呼叫它。在函式元件之前,您會像這樣撰寫 Elixir 範本
<div>
<%= modal(title: "Your file is ready!") do %>
The file will only be available for 10 minutes
<% end %>
</div>
這已經夠簡單了,但當我們希望在模態標題中放置任意內容時,例如下載連結,問題就會出現。我們最後嘗試將原始 HTML 字串串接在一起,而這並非長久之計
<div>
<%= modal(title: "Your #{"<a href=\"#{@url}\" download>file</a>"} is ready!") do %>
The file will only be available for 10 minutes
<% end %>
</div>
這會失敗,因為 Phoenix 會對字串執行 HTML 逸出,因此我們需要仔細解開我們自己的 HTML 輸入。傳統範本模型在可組成性方面會瓦解。函式元件和插槽透過允許元件宣告命名插槽解決了這個問題,呼叫者可以在命名區段(例如模態標題、標頭或頁尾)中提供任意內容。讓我們使用函式元件和插槽重新撰寫上述範例
<div>
<.modal>
<:title>
Your <.link href={@url} download>file</.link> is ready!
</:title>
The file will only be available for 10 minutes
</.modal>
</div>
現在我們開始看到函式元件和插槽的真正威力。函式元件可以在標記中完美組成,而且插槽允許呼叫者提供它們自己的任意結構,例如上面的 <:title>
插槽。在這裡,我們傳遞我們自己的標記內容,包括對其他函式元件的呼叫!這允許封裝的 UI 建構基塊彼此組成。不必再對每個使用案例執行任意字串串接或客製化嚴格範本。
插槽提供更強大的組合。插槽並未在元件中放置單一命名項目,而是集合,允許呼叫者為元件提供任意數量的插槽條目。例如,想像一個表格元件,呼叫者需要提供任意數量的表格欄位。這不可能與常見的靜態 HTML 範本抽象輕鬆組成,但有了插槽,讀寫起來就非常美妙
<.table id="files" rows={@files}>
<:col :let={file} label="Name"><%= file.name %></:col>
<:col :let={file} label="Size"><%= file.size %></:col>
<:action :let={file}>
<.link patch={~p"/files/#{file}/edit"}>Edit</.link>
</:action>
<:action :let={file}>
<.link phx-click={JS.push("delete", value: %{id: file.id})} data-confirm="Are you sure?">
Delete
</.link>
</:action>
</.table>
不直接寫入未處理的 <table>
標籤,或自訂函數,例如 <%= file_table(rows: @files)>
,我們可以善加利用槽來在應用程式中定義單一 <.table>
函數元件,其接受 <:col>
和 <:action>
槽。注意我們如何在上面傳遞多個欄和動作?這便是槽的一大亮點。內部表格可以根據我們提供的每一個 <:col>
label
渲染出 <thead>
和 <th>
項目。接著,為渲染每列,元件只會遍歷我們傳遞的每個 rows
,根據每個我們 <:col>
的欄和內部內容渲染出欄。與撰寫未處理的 HTML 以及到處複製風格和標籤相比,如此書寫標記輕鬆許多,且可重複使用。您會發現一旦在應用程式中建立好一組核心 UI 元件後,您很少需要使用新的功能擴充元件,這是由於元件和槽的組成。
這些看起來真的都很棒,但是隨著逐步增加更多屬性和槽,我們如何發現實際上具備哪些支援?對於使用此類元件,我們能有多大的信心?這時,宣告式指定和槽的登場替編譯器做好了後盾。
宣告式指定和槽
歸功於 Marlus Saraiva 在 Surface 函式庫中開創這些功能並為 LiveView 做出貢獻,元件已被提升到可用性與生產力的新境界。
讓我們跳回我們的模態對話窗,看看如何辦到。假設我們想要在對話窗於頁面載入時立即自動顯示,而不是稍後以程式化方式顯示。假設團隊中有人適當地記載了這個函數,我們可以進行探勘,或許能找到搭配 show
屬性以自動顯示對話窗的範例。但即使有最好的文件記載,也無法排除我們輸入錯誤或屬性或槽有誤。例如,想像我們錯誤輸入 <.modal autoshow>
。
還好,編譯器替我們把關!這裡我們看到我們的 autoshow
是個未知屬性,而且我們得知程式遺漏了必要的 id
屬性。我們會即時地在編輯器內收到這則回饋,而不是等到執行時間出現錯誤。
有了宣告式指定和槽,函數元件會一併指定它們所接受的屬性、類型和槽,並附上內嵌文件。這不只能提供進階文件,而且會在每次呼叫元件時執行編譯時間驗證以提供回饋。從此不必再靠擲飛刀,或靠猜測來執行。這也允許社群推出一流的 UI 函式庫,讓使用者在建立應用程式的同時可以快速上手。以下示範它實際執行的狀況
HEEx HTML 格式化程式
多虧 Feelipe Renan 的出色工作,現在在執行 mix format
時,你的 .heex
檔案和應用程式中的任何 ~H
範本都將採用 HTML 格式。這非常有幫助,因為你的標記和函式元件已內嵌 Elixir 表達式,而你希望這些表達式以正規規則進行格式化,就像其他 Elixir 程式碼一樣。HEEx 格式器會處理所有情況,包括一般標記格式化、標籤內 Elixir 表達式格式化,以及 EEx 內容中的 Elixir 表達式格式化 <%= %>
。格式器還會確保前端和後端開發人員遵循應用程式中統一的編碼指南。
讓我們看看實際運作
可存取性
LiveView 應為所有使用者提供絕佳的網路體驗,包括有螢幕閱讀器存取需求的使用者。LiveView 0.18 包含幾個基礎元件來協助這部分,更多元件即將推出。
首先,我們發布一個新的 <.focus_wrap>
元件,讓你只要用 <.focus_wrap>...</.focus_wrap>
將任何範本內容包覆起來,即可讓 Tab 鍵在元件周圍循環。這聽起來可能很普通,但對於使用鍵盤導覽的螢幕閱讀器使用者來說,在顯示對話方塊和彈出式視窗時,這是一個重要的基礎元件。此外,這項功能通常需要開發人員透過自訂 JavaScript 來介入。讓我們看看實際運作
我們也發布了處理焦點狀態的新 JS 指令,包括 JS.focus
和 JS.focus_first
。這兩個指令都能讓你以程式化方式設定元件的焦點,但 JS.focus_first
特別好用,是一個設定好就不用管的指令,能從可存取性的角度執行正確的動作。它會在容器中找出第一個可以聚焦的元件,將焦點設定在那裡,無需你費心思考。例如,彈出一個 modal 對話方塊時,你不用考慮這個 modal 對話方塊有一個情況下有表單輸入,或者另一種情況下只有確認/取消按鈕。只要使用這個指令找到第一個要聚焦的地方,LiveView 就會將焦點放在那裡。
你的 show modal 函式可能看起來像這樣
def show_modal(js \\ %JS{}, id) when is_binary(id) do
js
|> JS.show(to: "##{id}")
|> JS.show(to: "##{id}-bg")
|> show("##{id}-container")
|> JS.focus_first(to: "##{id}-container")
end
現在,應用程式中任何顯示 modal 對話方塊的地方都會在該 modal 對話方塊內聚焦。搭配 <.focus_wrap>
和 phx.new
會產生的 aria 標籤,螢幕閱讀器使用者在使用你的應用程式時,會享有完全可存取的 modal 對話方塊。
非作用檢視中的 JS 指令和勾子
JS 命令是另一項宣告式 LiveView 功能,讓您可以在客戶端操作 DOM,而不必前往伺服器。它們特別適用於顯示模式對話方塊和下拉式選單、傳送事件、動畫處理及切換屬性,但到目前為止這些都是 LiveView 的特定功能。一般的靜態檢視也共用這些相同的用例,因為人們想要在沒有自訂 JavaScript 或引入架構的情況下顯示或隱藏內容。LiveView 0.18 現在包含對 JS 命令和 LiveView 外部所呈現內容內部掛鉤的支援。這使得您許多的核心 UI 功能元件可以在 LiveView 或一般檢視中使用,例如模式對話方塊、快訊及下拉式選單。
我們對於此版本和它帶來的生產力改善感到非常興奮,而且我們迫不及待地想展示 Phoenix 1.7 應用程式即將啟用所有新穎的事物。
請保持關注並持續編寫程式碼!
–Chris