如何在 Go 的 html/template 中正确传递数据到被包含的模板

在 go 的 `html/template` 中,使用 `{{ template "name" }}` 语法包含子模板时,默认不会自动继承父模板的数据上下文;必须显式传入当前上下文(如 `.`)才能使变量在子模板中可用。

当你在 index.tpl 中写 {{ template "head" }},Go 模板引擎会以 空上下文(nil) 执行 "head" 模板——这意味着 {{ .Title }} 在 head.tpl 中求值为 ""(空字符串),因此

标签内容为空。<p>✅ 正确做法是:<strong>显式将当前数据结构传递给被包含的模板</strong>:</p><pre class="brush:php;toolbar:false;">{{ template "head" . }}</pre><p>其中 . 表示当前执行上下文(即 Page{Title: "This is title", Desc: "Desc"}),这样 head.tpl 就能正常访问 .Title 和 .Desc。</p> <p>? 修改后的 index.tpl(关键行已加粗):</p><pre class="brush:php;toolbar:false;">{{ define "index" }} <html lang="en"> **{{ template "head" . }}** <body> <h1>Main info:</h1> Title: {{ .Title }} Desc: {{ .Desc }} </body> </html> {{ end }}</pre><p>无需改动 head.tpl,它保持原样即可:</p><pre class="brush:php;toolbar:false;">{{ define "head" }} <head> <meta charset="UTF-8"> <title>{{ .Title }} {{ end }}

⚠️ 注意事项:

  • {{ template "name" }}(无参数) → 子模板接收 nil 上下文;
  • {{ template "name" . }} → 子模板接收与父模板相同的结构体实例;
  • 若需传入部分字段或新结构,也可用 {{ template "name" map "title" .Title }} 或自定义结构体,但通常直接传 . 最简洁可靠;
  • 所有被 define 声明的模板(如 "head")都是独立作用域,不共享上下文,必须显式传递。

? 小技巧:你还可以在包含时临时修改上下文,例如 {{ template "head" (struct{Title string}{"Custom Title"}) }},适用于需要定制化渲染的场景。

总结:Go 模板的 template 动作默认不透传数据,这是设计上的显式性保障——避免隐式依赖和意外行为。养成 {{ template "xxx" . }} 的习惯,是编写健壮、可维护模板的基础。