🐥
Phoenix LiveView PC/SPスマホサイズで画面を出し分ける一案
PCとスマホでHTMLを出し分ける1つの方法案です。
この記事はElixir Advent Calendar 2023の1つです。カレンダーも是非ご覧ください!
要点
- LiveSocket接続時のparamsにユーザー画面サイズの情報を入れ込む。
-
get_connect_params/1
で情報を取る。 - よしなに変数に入れて出し分ける。
LiveSocket接続時にクライアント情報を送る
素のコードでもcsrf_token
を取得して送っています。ここにクライアントサイズを送るコードを追加します。
import topbar from "../vendor/topbar"
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
-let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
+let clientWidth = document.body.clientWidth
+let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken, width: clientWidth}})
// Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
- 注意:LiveSocket接続時のみなので、例えば現在のURLを取るなどには使えません。
- その他にローカルタイムなどの取得ができそうです。
- UserAgentは別途取得可能です。https://hexdocs.pm/phoenix/Phoenix.Socket.Transport.html#connect_info/3
マウント時に送った情報を受け取る
paramsに入った情報はget_connect_params(socket)["width"]
で取れます。
例えば、全体で使うならばon_mount
で処理を行い、適当にアサインしておきます。
下記ではPhxPcSpWeb.InitAssigns
にon_mount
を用意して@sp
と@pc
を判定で使えるようにアサインしています(排他的なので1変数でいい、などその辺りはよしなにどうぞ)。
live_session :default, on_mount: [PhxPcSpWeb.InitAssigns] do
scope "/", PhxPcSpWeb do
pipe_through :browser
live "/", PageLive, :show
end
end
defmodule PhxPcSpWeb.InitAssigns do
@moduledoc """
Ensures common `assigns` are applied to all LiveViews attaching this hook.
"""
import Phoenix.LiveView
import Phoenix.Component
@sp_screen_size 640
def on_mount(:default, _params, _session, socket) do
width = get_connect_params(socket)["width"]
{:cont, assign(socket, get_client_view(width))}
end
defp get_client_view(width) when width > @sp_screen_size do
%{sp: false, pc: true}
end
defp get_client_view(_width) do
%{sp: true, pc: false}
end
end
HTMLを出し分ける
あとは@pc
と@sp
を使って判定するだけです。
以下は、頭からPC/SPを出し分けている例です。embed_templates
を使っています。
defmodule PhxPcSpWeb.PageLive do
use PhxPcSpWeb, :live_view
embed_templates "show/*"
def render(%{pc: true} = assigns), do: ~H"<.pc {assigns} />"
def render(%{sp: true} = assigns), do: ~H"<.sp {assigns} />"
def mount(_params, _session, socket) do
{:ok, socket}
end
end
PCならshow/pc.html.heex
が、SPならshow/sp.html.heex
が描画されます。
(とはいえ実験してみたまでで実用していません - - )
Discussion