🐥

Phoenix LiveView PC/SPスマホサイズで画面を出し分ける一案

2023/12/01に公開

PCとスマホでHTMLを出し分ける1つの方法案です。

この記事はElixir Advent Calendar 2023の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)"})

マウント時に送った情報を受け取る

paramsに入った情報はget_connect_params(socket)["width"]で取れます。

例えば、全体で使うならばon_mountで処理を行い、適当にアサインしておきます。
下記ではPhxPcSpWeb.InitAssignson_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