我們來用一個簡單加減數字的網頁互動計數器來理解 LiveView 的構造
還是要有路徑啦,只是這次路徑指定的目的地不是 controller,而是一個 LiveView 模組
lib/blog_web/router.ex
scope "/", BlogWeb do
pipe_through(:browser)
resources("/notes", NoteController)
resources("/posts", PostController)
# 使用 live 方法將 "/counter" 指定到 CounterLive 模組
live("/counter", CounterLive)
get("/", PageController, :index)
end
既然都指了,就要把他補上
通常 LiveView 都會放在跟 controllers 資料夾同級的 live 資料夾裡
以我們的專案來看是 lib/blog_web/live
在 lib/blog_web/live
資料夾裡面建立 counter_live.ex
來裝我們這次要使用的 CounterLive 模組
lib/blog_web/live/counter_live.ex
defmodule BlogWeb.CounterLive do
# 使用 BlogWeb 裡面的 live_view 模組們
use BlogWeb, :live_view
# mount 是每次 LiveView 頁面一連線會執行的地方,我們待會會在這邊初始 LiveView 的狀態
def mount(_params, _session, socket) do
{:ok, socket}
end
# 準備顯示在頁面上的內容
def render(assigns) do
~H"""
<h1>簡陋計數器</h1>
"""
end
end
這樣其實就只是一個不會動的普通頁面,不過我們先把需要的零件加進去 render 方法裡面
def render(assigns) do
~H"""
<h1>簡單計數器</h1>
<section>
<h1>0</h1>
<button>+</button>
<button>-</button>
</section>
"""
end
接著我們要把畫面上寫死的 0 改由狀態管理,
LiveView 的頁面狀態都放在 socket 裡面的 assigns
我們可以用 assign
方法把 我們要放的 key value 值放進去
def mount(_params, _session, socket) do
socket = assign(socket, :number, 0)
{:ok, socket}
end
一但有值在 assigns 裡面,他就可以在 render 裡用取用
這次來說我們在加了 :number
所以在 render 的 ~H sigil 裡面可以使用 @number 來取他的值
def render(assigns) do
~H"""
<h1>簡單計數器</h1>
<section>
<h1><%= @number %></h1>
<button>+</button>
<button>-</button>
</section>
"""
end
有寫過前端框架的朋友可能會開始覺得這個套路有點熟悉,
沒錯,接下來我們要在 上面綁上動作來操作狀態
def render(assigns) do
~H"""
<h1>簡單計數器</h1>
<section>
<h1><%= @number %></h1>
<button phx-click="plus">+</button>
<button phx-click="minus">-</button>
</section>
"""
end
好了之後,我們要用 handle_event 這個 callback 方法來接這兩個事件
def handle_event("plus", _params, socket) do
# 從 socket 的 assigns 的 number 拿到加之前的數字 然後加一
new_number = socket.assigns.number + 1
# 在這邊用 assign 再幫 :number 上新的值
socket = assign(socket, :number, new_number)
# handle_event 用的是 :noreply,代表他只有單純更新 socket,畫面則是統一由 LiveView 依照狀態來與瀏覽器溝通更新
{:noreply, socket}
end
# 跟上面一樣只是換成 -
def handle_event("minus", _params, socket) do
socket = assign(socket, :number, socket.assigns.number - 1)
{:noreply, socket}
end
這樣就完成啦!
按下按鈕改變 number 的狀態,畫面上就會自動更新,不需要自己去改變 DOM