查看源代码 实时导航

LiveView 提供功能,允许使用 浏览器的 pushState API 进行页面导航。使用实时导航,页面会在不完全重新加载的情况下更新。

您可以通过两种方式触发实时导航

例如,在模板中,您不必编写以下内容

<.link href={~p"/pages/#{@page + 1}"}>Next</.link>

您可以编写

<.link patch={~p"/pages/#{@page + 1}"}>Next</.link>

或在 LiveView 中

{:noreply, push_patch(socket, to: ~p"/pages/#{@page + 1}")}

当您想要导航到当前 LiveView 时,必须使用“patch”操作,只需更新 URL 和当前参数,而无需挂载新的 LiveView。使用 patch 时,会调用 handle_params/3 回调,并将最小的更改集发送到客户端。有关更多信息,请参见下一节。

当您想要卸载当前 LiveView 并挂载新的 LiveView 时,必须使用“navigate”操作。您只能在同一个会话中“导航”不同的 LiveView。在重定向时,会在 LiveView 中添加 phx-loading 类,可以用来指示用户正在加载新页面。

如果您尝试修补到另一个 LiveView 或跨实时会话导航,将会触发完全的页面重新加载。这意味着您的应用程序将继续工作,以防您的应用程序结构发生变化,而这些变化没有反映在导航中。

下面是快速分解

  • <.link href={...}>redirect/2 是基于 HTTP 的,可以在任何地方工作,并且会执行完整的页面重新加载

  • <.link navigate={...}>push_navigate/2 在同一个会话中跨 LiveView 工作。它们会挂载新的 LiveView,同时保留当前布局

  • <.link patch={...}>push_patch/2 会更新当前 LiveView,并仅发送最小的差异,同时也会保留滚动位置

handle_params/3

mount/3 之后,在初始渲染之前,会调用 handle_params/3 回调。每当使用 <.link patch={...}>push_patch/2 时,也会调用它。它将请求参数作为第一个参数接收,将 url 作为第二个参数接收,并将套接字作为第三个参数接收。

例如,假设您有一个 UserTable LiveView 用于显示系统中的所有用户,您在路由器中将其定义为

live "/users", UserTable

现在要添加实时排序,您可以执行以下操作

<.link patch={path(~p"/users", sort_by: "name")}>Sort by name</.link>

单击后,由于我们正在导航到当前 LiveView,因此会调用 handle_params/3。请记住,您永远不应该信任接收到的参数,因此您必须使用回调来验证用户输入并相应地更改状态

def handle_params(params, _uri, socket) do
  socket =
    case params["sort_by"] do
      sort_by when sort_by in ~w(name company) -> assign(socket, sort_by: sort_by)
      _ -> socket
    end

  {:noreply, load_users(socket)}
end

请注意,我们返回了 {:noreply, socket},其中 :noreply 表示不会向客户端发送任何额外信息。与其他 handle_* 回调一样,对 handle_params/3 内部的状态进行的更改会触发新的服务器渲染。

请注意,传递给 handle_params/3 的参数与传递给 mount/3 的参数相同。那么您如何决定使用哪个回调来加载数据呢?一般来说,数据应该始终在 mount/3 上加载,因为 mount/3 在每个 LiveView 生命周期中只调用一次。只有您希望通过 <.link patch={...}>push_patch/2 更改的参数必须在 handle_params/3 上加载。

例如,假设您有一个博客。单个帖子的 URL 为:"/blog/posts/:post_id"。在帖子页面中,您有评论,并且它们是分页的。您使用 <.link patch={...}> 在用户每次分页时更新显示的评论,将 URL 更新为 "/blog/posts/:post_id?page=X"。在此示例中,您将在 mount/3 上访问 "post_id",并在 handle_params/3 上访问评论页面。

替换页面地址

LiveView 还允许替换当前浏览器 URL。当您希望某些事件更改 URL 但又不想污染浏览器的历史记录时,这很有用。这可以通过将 <.link replace> 选项传递给任何导航帮助器来完成。

同一页面中的多个 LiveView

LiveView 允许您在同一页面中拥有多个 LiveView,方法是在模板中调用 Phoenix.Component.live_render/3。但是,只有在路由器中直接定义的 LiveView 才能使用此处描述的“实时导航”功能。这一点很重要,因为 LiveView 与您的路由器紧密配合,保证您只能导航到已知的路由。