Tailwind CSS 前編 -- YouTube チャンネル namba.ex 第3回解説
動画
前回の続きです。
ライブコーディング(1)
前回の動画では、ブラウザの画面に表示されている円板をユーザーがクリックするとランダムに大きさが変わっていくところまでを作りました。
今回の動画では、ユーザーがクリックすると円板の色がランダムに切り替わるようにアプリケーションを作り変えていきます。
修正対象となるファイルは、次の2つです:
lib/dynamic_disc_web/live/demo_live.html.heex
lib/dynamic_disc_web/live/demo_live.ex
修正前の demo_live.html.heex
は次の通りです:
<main>
<div class="p-4">
<%= @diameter %>,
"<%= @bg_color %>"
</div>
<div class="flex justify-around">
<div
phx-click="change_state"
class="bg-red-500 rounded-full cursor-pointer"
style={"width: #{@diameter}px; height: #{@diameter}px"}
>
</div>
</div>
</main>
まず、10行目の class
属性の値("bg-red-500 rounded-full cursor-pointer"
)をプライベート関数 get_class/0
として抜き出し、demo_live.html.ex
の末尾に追加しました。
...
def handle_event("change_state", _params, socket) do
socket =
socket
|> assign(:diameter, Enum.random(50..300))
|> assign(:bg_color, "")
{:noreply, socket}
end
defp get_class() do
"bg-red-500 rounded-full cursor-pointer"
end
end
そして、このプライベート関数 get_class/0
を用いて、demo_live.html.heex
を修正しました。
<main>
<div class="p-4">
<%= @diameter %>,
"<%= @bg_color %>"
</div>
<div class="flex justify-around">
<div
phx-click="change_state"
class={get_class()}
style={"width: #{@diameter}px; height: #{@diameter}px"}
>
</div>
</div>
</main>
続いて、get_class 関数を後で使いやすいように少し書き換えました。
...
def handle_event("change_state", _params, socket) do
socket =
socket
|> assign(:diameter, Enum.random(50..300))
|> assign(:bg_color, "")
{:noreply, socket}
end
@class_tokens ~w(
bg-red-500
rounded-full
cursor-pointer
)
defp get_class() do
Enum.join(@class_tokens, " ")
end
end
@class_tokens
で始まる4行では、モジュール属性を定義しています。他のプログラミング言語で言う「定数」あるいは「マクロ」に当たります。
~w( ... )
のように書くと、カッコで囲まれた部分が文字列のリストとして解釈されます。つまり、
"bg-red-500"
, "rounded-full"
, "cursor-pointer"
という 3 個の文字列を要素として持つリストがで
きます。これを関数 Enum.join/2
で連結しています。
この時点では、アプリケーションの振る舞いに変化はありません。
ライブコーディング(2)
次に、demo_live.ex
を次のように書き換えました。
...
def handle_event("change_state", _params, socket) do
socket =
socket
|> assign(:diameter, Enum.random(50..300))
|> assign(:bg_color, "bg-red-500")
{:noreply, socket}
end
@class_tokens ~w(
rounded-full
cursor-pointer
)
defp get_class(bg_color) do
tokens = [bg_color | @class_tokens]
Enum.join(tokens, " ")
end
関数 get_class
のアリティ(引数の数)を 0 から 1 に変えました。
リスト @class_tokens
の先頭に token
を加えてできる新たなリストを変数 tokens
に加えています。仮引数 bg_color
には "bg-red-500"
が渡ってくるので、実質的に関数 get_class
の振る舞いは変化していません。
tokens = [bg_color | @class_tokens]
は、Elixirの独特の書き方です。次の例を見ると、角カッコとパイプ文字の使い方が理解できるでしょう:
a = ["x", "y", "z"]
b = ["w" | a]
上記のコードを評価すると、変数 b
に ["w", "x", "y", "z"]
がセットされます。
続いて、demo_live.html.heex
を修正しました。
<main>
<div class="p-4">
<%= @diameter %>,
"<%= @bg_color %>"
</div>
<div class="flex justify-around">
<div
phx-click="change_state"
class={get_class(@bg_color)}
style={"width: #{@diameter}px; height: #{@diameter}px"}
>
</div>
</div>
</main>
ライブコーディング(3)
最後に、円板の色がランダムに変化するように、ソースコードを書き換えました。
...
@background_colors ~w(
bg-red-500
bg-green-500
bg-blue-500
bg-cyan-500
)
def handle_event("change_state", _params, socket) do
bg_color = Enum.random(@background_colors)
socket =
socket
|> assign(:diameter, Enum.random(50..300))
|> assign(:bg_color, bg_color)
{:noreply, socket}
end
@class_tokens ~w(
rounded-full
cursor-pointer
)
defp get_class(bg_color) do
tokens = [bg_color | @class_tokens]
Enum.join(tokens, " ")
end
注目すべきは、bg_color = Enum.random(@background_colors)
です。モジュール属性 @background_colors
には、赤、緑、青、シアンにする Tailwind CSS のクラストークンのリストがセットされています。関数 Enum.random/1
を用いてその中からランダムに1つを取り出しています。
上記の書き換えの結果、ユーザーが円板内をクリックするたびに、色がランダムに変化するようになりました。
ただし、動画内でも触れたように、4 分の 1 の確率で、現在の色と同じ色が選ばれてしまうので、クリックしたのに色が変化しないという現象が発生します。この問題には次回の動画で対応します。
Discussion