Phoenix LiveView 介绍

2026-02-21 06:24:12

什么是 LiveView?Phoenix LiveView 是 Elixir/Phoenix 框架下的一种模式,用来构建无需 JavaScript 的高交互网页。其主要特点包括:

运行在 服务器端的组件化 UI

通过 WebSocket 实现 页面局部更新

类似于 React 的状态驱动渲染,但渲染逻辑在服务器端完成

零 JS 也能做出动态交互:表单验证、实时列表等

LiveView 把我们过去需要写 JS 和前后端通信才能做的事,变成纯后端代码就能完成的工作

LiveView 应用演示任务列表

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182defmodule LiveViewDemoWeb.TodoLive do use LiveViewDemoWeb, :live_view import Ecto.Query alias LiveViewDemo.Task alias LiveViewDemo.Repo @topic "todo" def render(assigns) do ~H"""

Todo List

    <%= for task <- @tasks do %>
  • <%= task.title %>
  • <% end %>
""" end def mount(_params, _session, socket) do Phoenix.PubSub.subscribe(LiveViewDemo.PubSub, @topic) {:ok, assign(socket, tasks: list_tasks(), title: "")} end def handle_event("add", %{"title" => title}, socket) do if String.trim(title) != "" do %Task{title: title, completed: false} |> Repo.insert() Phoenix.PubSub.broadcast(LiveViewDemo.PubSub, @topic, :tasks_updated) end {:noreply, assign(socket, tasks: list_tasks(), title: "")} end def handle_event("delete", %{"id" => id}, socket) do task = Repo.get!(Task, id) Repo.delete!(task) Phoenix.PubSub.broadcast(LiveViewDemo.PubSub, @topic, :tasks_updated) {:noreply, assign(socket, tasks: list_tasks())} end def handle_event("toggle", %{"id" => id}, socket) do task = Repo.get!(Task, id) {:ok, _} = task |> Ecto.Changeset.change(completed: !task.completed) |> Repo.update() Phoenix.PubSub.broadcast(LiveViewDemo.PubSub, @topic, :tasks_updated) {:noreply, assign(socket, tasks: list_tasks())} end def handle_info(:tasks_updated, socket) do {:noreply, assign(socket, tasks: list_tasks())} end defp list_tasks do Repo.all(from t in Task, order_by: [desc: t.inserted_at]) endend

用户注册表单

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152defmodule LiveViewDemoWeb.RegistrationLive do use LiveViewDemoWeb, :live_view alias LiveViewDemo.Accounts.User alias LiveViewDemo.Repo def render(assigns) do ~H""" <.simple_form for={@changeset} as={:user} id="registration_form" phx-change="validate" phx-submit="save" class="space-y-6" :let={f} > <.input field={f[:username]} label="Username" /> <.input field={f[:password]} type="password" label="Password" /> <:actions> <.button phx-disable-with="Registering..." class="w-full"> Register """ end def mount(_params, _session, socket) do {:ok, assign(socket, changeset: User.changeset(%User{}, %{}))} end def handle_event("validate", %{"user" => user_params}, socket) do changeset = %User{} |> User.changeset(user_params) |> Map.put(:action, :validate) {:noreply, assign(socket, changeset: changeset)} end def handle_event("save", %{"user" => user_params}, socket) do case Repo.insert(User.changeset(%User{}, user_params)) do {:ok, _user} -> socket = put_flash(socket, :info, "Registration successful!") {:noreply, push_navigate(socket, to: "/")} {:error, changeset} -> {:noreply, assign(socket, changeset: changeset)} end endend

其他https://github.com/jinhucheung/live_view_demo/tree/main/lib/live_view_demo_web/live

LiveView 要解决哪些痛点?对于大部分传统 MVC 后端框架,如果要实现:

实时表单验证

动态页面交互

必须写 JavaScript:

用 JS 监听事件

用 AJAX 发送请求

写后端接口返回 JSON

JS 再根据数据更新 DOM

在这个过程中会有下面问题:

前后端割裂

状态同步困难

维护成本高

动态交互门槛高

LiveView 旨在解决传统后端框架中遇到的上述问题,提升实时交互应用开发的体验,减少开发和维护成本

LiveView 是否解决了这些问题?LiveView 优势:

满足大部分实时交互需求:实时性强,WebSocket 提供流畅体验

高效的开发体验:只需要开发维护一套后端代码,状态完全由后端控制

SEO 友好:首屏加载返回 HTML

出色的性能:仅传输最小化 diff patches 减少了带宽和延迟;基于 Erlang/Elixir 每个用户连接都是独立轻量的进程,天生适合处理高并发;不需要引入前端框架,降低了前端渲染的开销

LiveView 劣势:

无法离线使用,不适合复杂的客户端应用(如 Figma)

高频交互(如拖拽、动画) 场景下,由于所有事件都需往返服务器,可能不如纯前端流畅

LiveView 核心的技术机制

页面初始加载是 HTML 渲染(传统方式)

后续交互走 WebSocket,每个事件都是消息 (phx-* 事件) 传回后端服务器处理

LiveView 内部维护 socket 状态,每次更新后只发送最小化 diff patches

客户端接收到数据后,通过 LiveView 内置的 JS 框架对 DOM 结构进行更新,调用相应的 JS hooks (phx-hook)

引用

LiveView HexDoc

Phoenix LiveView 1.0.0 is here!

Phoenix LiveView 简介

phoenix_live_view_example