很遺憾,工作要做的畫面大部分都是表格,在我們開始做酷東西之前,我們先確認一下 LiveView 可不可以達成工作要求
我們可以使用一樣的 Post context
我們也可以用新的取代掉 resources("/posts", PostController)
,但這次我們先用個不同的路徑
為 lib/blog_web/router.ex
加上 live("/live_posts", PostLive.Index)
scope "/", BlogWeb do
pipe_through(:browser)
resources("/notes", NoteController)
resources("/posts", PostController)
live("/counter", CounterLive)
live("/live_posts", PostLive.Index) # 加在這邊
get("/", PageController, :index)
end
一樣,路徑幫我們導到 PostLive.Index 模組,我們來建立一個lib/blog_web/live/post_live/index.ex
通常 elixir 模組名稱會與他的路徑相對應,但方便整理就行了BlogWeb.PostLive.Index
defmodule BlogWeb.PostLive.Index do
# 引用 BlogWeb 裡的 live_view
use BlogWeb, :live_view
# alias 之前做的 Blog.Posts,稍後比較方便呼叫
alias Blog.Posts
# 在 mount 裡面 assign 所有的文章
def mount(_params, _session, socket) do
{:ok, assign(socket, :posts, Posts.list_posts())}
end
def render(assigns) do
~H"""
<h1>LiveView 文章列表</h1>
<%= for post <- @posts do %>
<%= post.title %>
<% end %>
"""
end
列表做好了
好啦有點太簡單,我們在這邊開始用 component 來幫他延伸
component 就是一個收 assigns 變數,然後裡面有 sigil_H 的方法
使用的時候我們可以在另一個 sigil_H(~H""" """) 裡面使用 <>
來呼叫
def render(assigns) do
~H"""
<h1>LiveView 文章列表</h1>
<table>
<.table_head />
<.table_body>
<%= for post <- @posts do %>
<.post_row post={post} />
<% end %>
</.table_body>
</table>
"""
end
# 這是一個最簡單的 component 因為他就是單純的把一些 HTML 整理起來
def table_head(assigns) do
~H"""
<thead>
<tr>
<th>標題</th>
<th>內容預覽</th>
<th>動作</th>
</tr>
</thead>
"""
end
# 普通的 component 有 /> 結尾,如果想要包別的東西可以用
# <.table_body>
# 內容
# </.table_body>
#
# 我們可以用 `render_slot(@inner_block)` 來顯示內容
def table_body(assigns) do
~H"""
<tbody>
<tr>
<%= render_slot(@inner_block) %>
</tr>
</tbody>
"""
end
def post_row(assigns) do
~H"""
<tr>
<td><%= @post.title %></td>
<td><%= String.slice(@post.body, 0..25) <> "..." %></td>
<td>
閱讀
編輯
刪除
</td>
</tr>
"""
end
end
要注意的是 Component 在之前傳統 Controller View Template 裡的 template 裡面也可以使用
另外如果呼叫一個 Component 就跟普通方法一樣,如果是定義在不同的 Module,就需要寫出該 Module 名稱,如:
<AnotherModule.function_name />