這邊我有寫額外的 css 來正確顯示待會要用到的 modal
專案的 css 都放在 assets/css 資料夾裡
建立一個新的 css 檔案assets/css/fast_phoenix.css
.modal-background {
position: fixed;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
}
.modal {
background-color: white;
width: fit-content;
height: fit-content;
min-width: 600px;
min-height: 300px;
padding: 2rem;
border-radius: 0.5rem;
position: relative;
}
.esc-button {
width: fit-content;
height: fit-content;
position: absolute;
top: 1rem;
right: 1rem;
}
有了之後在 assets/css/app.css
前面加上這兩行來 import
/* import 這系列用到的 css 檔案 */
@import "./fast_phoenix.css";
上一篇我們使用了 component 來整理重複使用的片段,普通的 component 給他什麼值他就會畫出對應的結果,
我們這次要介紹的 Live Component 則不一樣,他有自己的狀態,自己的動作,有點像是一個小型的 LiveView 頁面。
我們可以做一個叫做 BlogWeb.PostLive.Form 的 Live Component/lib/blog_web/live/post_live/form.ex
defmodule BlogWeb.PostLive.Form do
# 這邊跟 live view 不一樣的,他引用的是 live_component
use BlogWeb, :live_component
# 跟 live view 用 mount 不一樣,這邊用 update/2
def update(_assigns, socket) do
{:ok, socket}
end
# 一樣會使用 render 來輸出結果,這邊要注意的是,live_component 外層一定要是一個 dom 元件,如這邊是一個 div
def render(assigns) do
~H"""
<div>
<.modal>
<h1>新增文章</h1>
</.modal>
</div>
"""
end
def modal(assigns) do
~H"""
<div phx-click="cancel_form" id="modal">
<div class="modal-background">
<div class="modal">
<button phx-click="cancel_form" class="esc-button">x</button>
<%= render_slot(@inner_block) %>
</div>
</div>
</div>
"""
end
end
這邊我們來觀察一下這個 modal component
def modal(assigns) do
~H"""
<div id="modal">
<div class="modal-background">
<div class="modal" phx-click-away="cancel_form">
<button phx-click="cancel_form" class="esc-button">x</button>
<%= render_slot(@inner_block) %>
</div>
</div>
</div>
"""
end
這邊 phx-click 是滑鼠按下去執行,phx-click-away 是滑鼠按不是這個元件時(外面的灰背景) 執行, 兩個都是去執行 "cancel_form" 這個關閉這個表格 modal 的事件,
要注意的是,儘管 live component 可以接收自己的事件,預設的事件還是會給上層使用他的 LiveView 頁面來接收。
下一篇我們會使用 target={@myself} 來改由 live component 本身來接收
有了 component 之後我們準備要把他加入 之前做的 Live 文章列表
我們可以使用 <.live_component module={模組名稱} id="幫他取一個id" />
來帶入
但在那之前我們先整理一下我們要達成什麼
我想要有一個新增文章的按鈕,按下去之後顯示我們的準備用來放表格的 Live Component
如果不送出可以按 X 或是 modal 旁邊的陰影來關閉。
要做的事情
編輯 lib/blog_web/live/post_live/index.ex
defmodule BlogWeb.PostLive.Index do
use BlogWeb, :live_view
alias Blog.Posts
def mount(_params, _session, socket) do
# 這邊再加上 form: false
# assign 如果是使用兩個變數版本,後面接的是 Map 可收多個 assign
{:ok, assign(socket, %{posts: Posts.list_posts(), form: false})}
end
# 取消表格用的 event
def handle_event("cancel_form", _params, socket) do
{:noreply, assign(socket, :form, false)}
end
# 開啟表格用的 event
def handle_event("show_form", _params, socket) do
{:noreply, assign(socket, :form, true)}
end
# `<button phx-click="show_form">新增文章</button>` 加上新文章按鈕
#
# 用 if @form 來判斷要不要使用 live component
#
def render(assigns) do
~H"""
<h1>LiveView 文章列表</h1>
<button phx-click="show_form">新增文章</button>
<%= if @form do %>
<.live_component module={BlogWeb.PostLive.Form} id="modal" />
<% end %>
<table>
<.table_head />
<.table_body>
<%= for post <- @posts do %>
<.post_row post={post} />
<% end %>
</.table_body>
</table>
"""
end
# 下面還有 thead 等等 component 這次不會改到
end