You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Elixir Phoenix中如何在同一eex文件定义<head>与<body>区块

Phoenix 框架多命名内容块实现方案

Phoenix 原生提供的插槽机制完全可以满足「布局多位置占位、子页面按名传自定义内容」的需求,不需要引入第三方依赖,从根源上避免多页面重复样板代码的问题。

1. 高版本Phoenix(1.7+)原生Slot方案

Phoenix 1.7 版本默认的 HEEx 模板引擎内置了完整的插槽能力,也是官方推荐的实现方式。

第一步:在公共布局中预留命名插槽

打开公共布局文件(通常路径为lib/你的项目名_web/components/layouts/root.html.heex),在所有需要支持逐页自定义的位置(<head>区、头部导航扩展位、侧边栏、页脚等),用render_slot/2预留插槽,同时可以配置插槽的默认兜底内容:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- head区自定义内容插槽 -->
  <%= render_slot(@head_extra) || do %>
    <title>站点默认标题</title>
    <meta name="description" content="站点默认SEO描述">
  <% end %>
  <!-- 全局固定资源统一放在布局中维护,不需要每个页面重复写 -->
  <link rel="stylesheet" href={~p"/assets/app.css"} />
  <script defer src={~p"/assets/app.js"}></script>
</head>
<body>
  <header class="site-header">
    <!-- 头部区域自定义扩展插槽 -->
    <%= render_slot(@header_extra) %>
  </header>
  <main class="main-container">
    <!-- 默认主内容渲染入口,和原有inner_content逻辑一致 -->
    <%= @inner_content %>
  </main>
  <footer class="site-footer">
    <!-- 页脚区域自定义扩展插槽 -->
    <%= render_slot(@footer_extra) %>
  </footer>
</body>
</html>

第二步:在业务页面中传入对应插槽内容

在具体的业务页面模板中,不需要修改控制器代码,直接用<:插槽名>标签给对应位置传入自定义内容即可,其余公共逻辑完全复用布局代码。以文章详情页为例:

<%!-- 传入head区专属SEO内容 --%>
<:head_extra>
  <title><%= @article.title %> - 我的技术博客</title>
  <meta name="description" content={@article.summary}>
  <meta name="keywords" content={Enum.join(@article.tags, ",")}>
</:head_extra>

<%!-- 传入头部区域专属面包屑导航 --%>
<:header_extra>
  <nav class="breadcrumb">
    <a href={~p"/"}>首页</a> / <a href={~p"/articles"}>文章列表</a> / <%= @article.title %>
  </nav>
</:header_extra>

<%!-- 页面主内容,和原有写法完全一致 --%>
<article class="article-detail">
  <h1><%= @article.title %></h1>
  <div class="content"><%= raw @article.content %></div>
</article>

<%!-- 传入页脚区域相关推荐模块 --%>
<:footer_extra>
  <section class="related">
    <h3>相关推荐</h3>
    <ul>
      <%= for post <- @related_posts do %>
        <li><a href={~p"/articles/#{post.id}"}><%= post.title %></a></li>
      <% end %>
    </ul>
  </section>
</:footer_extra>

2. 低版本Phoenix(1.6及更早)兼容方案

如果项目使用的是1.6及更早版本、没有HEEx模板的插槽能力,可以直接通过assign传值的方式实现相同效果:

  • 首先在公共布局中预留assign渲染位,做空值兜底:
<!-- 布局模板对应位置 -->
<%= if assigns[:custom_head], do: @custom_head %>
  • 在业务页面顶部直接给对应assign注入HEEx片段即可:
<%= assign(:custom_head, ~H"""
<title><%= @article.title %></title>
<meta name="description" content={@article.summary}>
""") %>

<!-- 后续写页面主内容即可 -->

所有全局公共的样板代码全部收敛到布局中统一维护,只有逐页差异的动态内容通过插槽传入,完全符合DRY原则,不会出现多页面重复维护相同代码的问题。

内容的提问来源于stack exchange,提问作者mmirate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:57:11