查看原始程式碼 Phoenix.LiveView.Engine (Phoenix LiveView v0.20.17)

追蹤變動的 EEx 範本引擎。

Phoenix.LiveView.TagEngine 常會用這個,它還會加上 HTML 驗證。在以下的文件中,我們將說明它的內部運作方式。使用者文件請參閱 Phoenix.LiveView

Phoenix.LiveView.Rendered

每當您呈現即時範本,它會傳回一個 Phoenix.LiveView.Rendered 結構。此結構有三個欄位::static:dynamic:fingerprint

:static 欄位是一個字串文字清單。藉此,Elixir 編譯器可以最佳化此清單,並避免在每次呈現時配置其字串。

:dynamic 欄位包含一個接收布林值引數的函數 (請參閱下列「追蹤變動」),並傳回一個動態內容清單。清單中的每個元素可能是下列其中之一

  1. Iodata - 這是動態內容
  2. nil - 動態內容沒有變更
  3. 另一個 Phoenix.LiveView.Rendered 結構,請參閱下列「巢狀結構和指紋」
  4. 一個 Phoenix.LiveView.Comprehension 結構,請參閱下列「理解」
  5. 一個 Phoenix.LiveView.Component 結構,請參閱下列「元件」

當您呈現即時範本時,您可以交替使用靜態欄位和動態欄位,將呈現結構轉換為 iodata,一律從靜態項目開始,後接一個動態項目。最後一個項目也會是靜態的。因此,下列結構

%Phoenix.LiveView.Rendered{
  static: ["foo", "bar", "baz"],
  dynamic: fn track_changes? -> ["left", "right"] end
}

會產生下列內容,並透過 iodata 傳送

["foo", "left", "bar", "right", "baz"]

這也是當您使用 Phoenix.HTML.Safe.to_iodata/1Phoenix.LiveView.Rendered 結構時,它傳回的結果。

當然,即時範本的好處就在於,您並不需要每次都傳送靜態和動態區段。所以,讓我們談談追蹤變動吧。

追蹤變動

預設情況下,即時範本不會追蹤變更。只要在指派項中加入包含金鑰 __changed__ 的已變更對應,並將 true 傳遞給動態部分即可啟用變更追蹤。對應應包含任何變更欄位的名稱為金鑰,以及布林值 true 為值的。如果欄位未列在 __changed__ 中,則它始終被視為未變更。

如果欄位未變更且即時認為動態表達式不再需要運算,則其在 dynamic 清單中的值會為 nil。這個資訊可以用於避免將資料傳送給客戶端。

巢狀處理和指紋辨識

Phoenix.LiveView 也會追蹤即時範本間的變更。因此,如果你的檢視具有以下內容

<%= render "form.html", assigns %>

Phoenix 將能夠追蹤範本之間的靜態和動態內容,以及這些內容有哪些變更。呈示的巢狀 live 範本會以另一個 Phoenix.LiveView.Rendered 結構出現在 dynamic 清單中,必須遞迴處理。

然而,因為即時範本的呈示本身也可能是動態的,因此有必要區分呈示的是哪個即時範本。例如,想像以下程式碼

<%= if something?, do: render("one.html", assigns), else: render("other.html", assigns) %>

為了解決這個問題,所有 Phoenix.LiveView.Rendered 結構也包含一個指紋欄位來標識它。如果指紋相等,則表示你具有相同的範本,因此有可能只傳送它的變更。

理解

即時範本執行的另一個最佳化是追蹤理解。如果你的程式碼具有以下內容

<%= for point <- @points do %>
  x: <%= point.x %>
  y: <%= point.y %>
<% end %>

它不會呈示具有靜態和動態部分的所有點,而是傳回一個 Phoenix.LiveView.Comprehension 結構,其中包含跨所有點共用的靜態部分,以及要在靜態部分內插入的動態清單。如果 @points 是包含 %{x: 1, y: 2}%{x: 3, y: 4} 的清單,上述表達式會傳回

%Phoenix.LiveView.Comprehension{
  static: ["\n  x: ", "\n  y: ", "\n"],
  dynamics: [
    ["1", "2"],
    ["3", "4"]
  ]
}

這讓即時範本可以大幅最佳化理解傳送的資料,因為靜態部分僅會傳送一次,不論項目數目為何。

動態清單總是 iodatas 或元件清單,因為我們不會在理解中執行變更追蹤。類似地,理解沒有指紋,因為它們僅在根部最佳化,因此像呈示中看到的條件評估是不可能的。傳回理解的動態欄位唯一可能出現的結果是 nil

元件

Live 也支援使用 Phoenix.LiveComponent 定義的有狀態元件。由於它們是有狀態的,所以總是以延遲方式由 diff 演算法處理。