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
相关产品推荐
相关产品推荐

