這個章節我們將介紹 EEx 以及 Phoenix 使用的 EEx 加強版, Heex。
Elixir 內建了 EEx (Embedded Elixir) 功能,讓我們可以在其他的 template (如:html
或 json
) 中使用 <%= %>
嵌入 Elixir 語法,我們可以在 iex 裡面執行以下程式碼來看看 EEx 的效果:
EEx.eval_string("你好, <%= @name %>", assigns: [name: "Jack"])
#=> "你好, Jack"
我們使用 <%= %>
來嵌入 Elixir 語法
<p>
<%= @note.content %>
</p>
要注意的是 <% %>
缺少 =
的版本們不回傳任何值,只是單純的執行 Elixir 程式碼。
<% "這個字串不會被顯示" %>
<% name = "不建議這樣但是可以" %>
(通常不會在 template 裡面做太多複雜的事情,如果需要的話可以考慮把邏輯移到 controller、 html module 或是其他通用 module。)
在 tempate 裡面的 if 或 if/else 判斷
<%= if @user.vip do %>
<p>你是 vip</p>
<% else %>
<p>歡迎</p>
<% end %>
注意這邊 else 與 end 使用 <% %>
在 heex 可以有的特別寫法
在 tempate 裡面的 for 迴圈
<%= for post <- @posts do %>
<li><%= post.title %></li>
<% end %>
不過在 Phoenix 中,我們不會直接使用 EEx,而是使用 Heex。
Heex 是 Phoenix 為了 HTML 特製的 template engine,是 EEx 針對 HTML 語法的加強版,除了我們目前使用 template 檔案 (檔名結尾為 index.html.heex) 之外,我們也可以使用 ~H
sigil 在 Elixir 程式中建立 Heex template(在後面的 LiveView 章節時與 Component 一起介紹)。
常用的功能以及 Heex 特有的語法:
Heex 會幫我們檢查裡面的 html 標籤是否成對,如:
<div>
<div>
</div>
這樣的寫法會被 Heex 檢查出來,並且會在編譯時顯示錯誤。
在 EEx 如果要在 html attribute 加入 elixir 語法我們必須:
<item id="<%= item.id %>">
在 Heex 我們可以直接使用 {}
來嵌入 elixir 語法:
<item id={item.id}>
:if
可以在 tag 使用 :if
attribute 來簡化畫面的判斷,如:
<p :if={user.vip}>你是 VIP</p>
:for
剛剛的 for 迴圈也可以使用 :for
attribute 來簡化:
原本的寫法:
<%= for post <- @posts do %>
<li><%= post.title %></li>
<% end %>
使用 :for
attribute:
<li :for={post <- @posts}><%= post.title %></li>
拿我們 index 中的 note 為例 (index.heex.html
)
<ul>
<li :for={note <- @notes}>
<%= note.content %>
</li>
</ul>
雖然目前 li 的內容算是簡單,但隨著功能與樣式增加,我們可能會想要把 li 的內容抽出來,這時候我們可以使用 Component。
我們先假裝這個 li 內容很多,並有用在不同的地方,所以我們把他拉出來成為一個 component。
在 lib/gratitude_web/controllers/note_html.ex
中新增一個 component 函式:
defmodule GratitudeWeb.NoteHTML do
use GratitudeWeb, :html
embed_templates "note_html/*"
def note_li(assigns) do
~H"""
<li><%= @note.content %></li>
"""
end
end
要使用在 heex 的 component 必先收 assigns,並且使用 ~H
sigil 來裝內容。
在 index.heex.html
使用時:
<ul>
<.note_li :for={note <- @notes} note={note}>
</ul>
Component 有更多的功能,我們會在後面的專用的章節介紹。
利用了上面提到的一些語法並加上造型,我們可以把 index.heex.html 改寫成:
<header class="my-4 border-b-4 border-amber-600">
<h1 class="text-xl font-bold text-amber-800">🙏 所有的感激筆記</h1>
</header>
<ul class="flex flex-col gap-4">
<li :for={note <- @notes} class="bg-amber-50 p-4 rounded-lg font-bold border-2 border-amber-300">
<%= note.content %>
</li>
</ul>