Gin嵌套模板必须显式定义名称并严格匹配:layout.html需{{define "layout"}}并{{template "main" .}},home.html须{{define "main"}}包裹内容,c.HTML(200, "home.html", data)渲染的是home.html中定义的块名而非文件名,data仅作用于该顶层块,子模板不可直接访问父级变量。

模板名必须显式定义,不能靠文件路径推导
嵌套模板不是自动识别的——layout.html 里用 {{template "main" .}},那 home.html 就必须以 {{define "main"}} 开头,否则 Gin 找不到该模板块,报错 template: "layout.html" is undefined。
常见错误是直接写 home.html 内容不加 {{define}},或者定义名和 {{template}} 中引用的名称不一致(比如写成 {{define "content"}} 却在 layout 里调用 {{template "main" .}})。
-
layout.html中必须包含{{define "layout"}}(或任意你命名的主块),并在其中用{{template "xxx" .}}引入子块 - 每个子模板(如
home.html)必须用{{define "xxx"}}包裹全部内容,且名字与{{template}}参数严格一致 -
LoadHTMLGlob("templates/**/*")会加载所有文件,但不会自动解析嵌套关系;定义名才是唯一匹配依据
c.HTML() 渲染的是“顶层模板名”,不是 layout 文件名
路由中调用 c.HTML(200, "home.html", data),Gin 实际渲染的是 home.html 里 {{define}} 的那个块(比如 "main"),再由它内部的 {{template "layout" .}} 拉入布局。你传的字符串 "home.html" 只是用来定位哪个文件里的 {{define}} 块,不是最终输出的 HTML 文件名。
这意味着:即使 home.html 只是一个纯 {{define "main"}} 块,没有 标签,也能正常工作——完整结构由 layout.html 提供。
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 如果误写成
c.HTML(200, "layout.html", data),Gin 会尝试渲染layout.html里{{define "layout"}}的内容,但里面{{template "main" .}}找不到数据上下文(因为没传子块),页面可能空白 - 子模板里不要重复写
等全局结构,只放 body 内容区 - 所有模板文件(layout 和子模板)都得放在
LoadHTMLGlob覆盖的路径下,否则{{template}}查不到
data 作用域只传给顶层 define 块,子块无法直接访问父级变量
你传给 c.HTML() 的 data(比如 gin.H{"Title": "首页", "User": user})只注入到被直接调用的 {{define}} 块(如 "main")中。如果 layout.html 里想用 {{.Title}},它拿不到——除非你在子块里显式把字段透传过去。
典型做法是在子模板开头手动展开:{{template "layout" .}} 是不够的,得写成 {{template "layout" (dict "Title" .Title "User" .User)}},前提是提前注册了 dict 函数;更稳妥的是在 layout 里用 {{with .Data}} 或约定统一字段名如 .Page。
- Gin 默认不带
dict函数,需手动注册:router.SetHTMLTemplate(template.Must(template.New("").Funcs(template.FuncMap{"dict": func(k string, v interface{}) map[string]interface{} { return map[string]interface{}{k: v} }}).ParseFiles("..."))) - 推荐结构体方式:定义
type PageData struct { LayoutData LayoutData; ContentData HomeData },避免字段冲突 - 别依赖
{{$.Title}}向上跨 scope 访问,Gin 模板引擎对$的支持不稳定,尤其嵌套深时容易失效
静态资源路径在嵌套模板里要统一用相对根路径
layout.html 里写的 <link href="/static/css/app.css"> 没问题,但如果你在 admin/user.html 里也写同样路径,它依然生效——因为浏览器解析的是最终合并后的 HTML,所有资源请求都相对于站点根目录(/),不是模板文件位置。
真正容易出错的是 router.Static() 配置和模板中路径不匹配。比如你注册了 r.Static("/assets", "./static/assets"),那模板里就必须写 /assets/css/xxx.css,而不是 ../static/assets/... 或 ./assets/...。
- 绝对路径(
/xxx)最安全,推荐全部用这种写法 - 千万别在子模板里写
../../static/...这类相对路径,Gin 不处理路径拼接,交给浏览器后 404 - 如果用了子路由分组(如
admin := r.Group("/admin")),静态资源仍要挂载在根路径,否则/admin下页面请求/admin/static/...会 404
{{define}} 是注册入口,{{template}} 是调用指令,c.HTML() 是启动开关,三者名字必须咬死。漏掉任一环,页面就空着,连错误提示都没有。


















