
在go的`html/template`中,使用`{{template}}`动作引入子模板(如header.html)时,默认不传递当前上下文数据;需显式写成`{{template "name" .}}`才能将父模板的数据(如page结构体)传入子模板。
当你在主模板 post.html 中写 {{template "header.html"}} 时,Go 模板引擎会以空数据(nil context) 渲染 header.html —— 这意味着 {{.Title}} 在子模板中求值为 "",而非你期望的 "I'm the title"。根本原因在于:{{template}} 动作本身不自动继承调用方的数据上下文,它是一个“无参调用”。
✅ 正确做法是显式传入当前上下文(即 .),修改 post.html 如下:
{{template "header.html" .}}
{{.Body}}
{{template "footer.html" .}} 这样,header.html 就能正常访问 {{.Title}} 和 {{.Body}} 等字段。
⚠️ 注意事项:
- . 表示当前模板执行时的根数据(此处即 Page{Title: "...", Body: "..."});
- 若子模板需要不同结构的数据(例如全局站点信息),可传入自定义 map 或结构体,如 {{template "header.html" (dict "Page" . "Site" $site)}}(需配合自定义函数);
- template 动作不会创建新的作用域,但会重置当前 . 的值为传入参数——因此务必确保传入的是你期望的上下文;
- 所有被 ParseGlob 加载的模板(包括 header.html、footer.html)必须属于同一 *template.Template 实例,否则 {{template}} 会报错 template: ... not defined。
? 小技巧:可在子模板开头加调试语句快速验证上下文是否正确:
{{if not .}}ERROR: context is nil!
{{end}}
{{.Title | default "Untitled"}}
总结:Go 模板的 {{template}} 是显式数据传递机制,而非隐式继承。牢记规则——要传数据,必带 .(或具体变量) ——这是避免“变量不可见”问题的核心原则。










