模板嵌套必须用{{template}}而非{{include}},因Go原生html/template不支持{{include}};所有嵌套需先{{define "name"}}声明,再{{template "name" .}}调用并显式传入上下文。

模板嵌套必须用 {{template}},不是 {{include}}
Go 原生 html/template 不支持 {{include}}(那是 Helm 或其他模板引擎的语法),Gin 继承这一限制。所有嵌套都靠 {{template "name" .}} 实现,且被嵌套的子模板必须先通过 {{define "name"}} 显式声明。
常见错误是直接写 {{include "header.html"}},运行时会报错:undefined: "include";或者漏掉 . (点加空格),导致子模板收不到当前上下文数据。
-
{{template "header" .}}—— 正确:把当前数据传给名为header的模板 -
{{template "header"}}—— 错误:子模板内{{.Name}}会是nil -
{{define "header"}}...{{end}}必须出现在被LoadHTMLFiles或LoadHTMLGlob加载的任一模板文件中,不能只放在未加载的独立文件里
LoadHTMLGlob 要覆盖全部模板文件,否则 {{template}} 找不到定义
Gin 不会自动扫描项目里所有 .tmpl 文件。如果你只调用 r.LoadHTMLGlob("templates/index.tmpl"),而 layout.tmpl 没被 glob 匹配到,那么即使 index.tmpl 里写了 {{template "layout" .}},启动时不会报错,但访问时会 panic:template: "index.tmpl":1: function "layout" not defined。
- 推荐统一用
r.LoadHTMLGlob("templates/**/*.tmpl")(注意双星号支持子目录) - 或显式列出:
r.LoadHTMLFiles("templates/layout.tmpl", "templates/index.tmpl", "templates/footer.tmpl") - 调试技巧:在
main()启动前加log.Println(r.Delims)和检查templates/目录是否真被读取(可临时删掉一个模板看是否报错)
继承结构建议用三段式:layout → section → content
避免在每个页面模板里重复写 <html><head> 等外壳。标准做法是抽离为 layout.tmpl,用 {{template "content" .}} 占位,再由具体页面(如 home.tmpl)只定义 {{define "content"}} 部分。
示例:
<!-- templates/layout.tmpl -->
<!DOCTYPE html>
<html>
<head><title>{{.Title}}</title></head>
<body>
{{template "header" .}}
<main>{{template "content" .}}</main>
{{template "footer" .}}
</body>
</html><!-- templates/home.tmpl -->
{{define "header"}}<h1>欢迎页</h1>{{end}}
{{define "content"}}<p>这里是主页正文:{{.Message}}</p>{{end}}
{{define "footer"}}<small>© 2026</small>{{end}}渲染时仍调用 c.HTML(200, "home.tmpl", data) —— Gin 会自动合并所有 define 块。
自定义函数在嵌套模板里照常可用,但要注意作用域
通过 r.SetFuncMap() 注册的函数(如 formatTime、truncate)对所有已加载模板全局生效,包括嵌套进来的 header 或 sidebar。
容易忽略的一点:如果某个子模板(比如 sidebar.tmpl)需要额外数据,但主模板传入的是结构体 PageData{Title, User, Posts},而 sidebar 只依赖 User,那就别在 {{template "sidebar" .}} 里硬塞整个结构体;更安全的做法是 {{template "sidebar" .User}},避免子模板意外访问 {{.Posts}} 导致 nil panic。
另外,{{template}} 不会触发新一次 FuncMap 查找,所以无需在每个子模板里重复注册。


















