Beego 中局部渲染通过 {{template}} 动作实现,路径以 views/ 为根目录、不支持 ../ 回退,需写全路径如 "zones/_form.tpl";推荐下划线前缀命名,数据宜用显式 map/结构体(如 .FormCtx)而非 . 全量传递,避免字段泄露。

Beego 中用 {{template}} 做局部渲染,不是写函数而是写路径
Beego 没有 partial 函数或专用语法,局部模板复用完全依赖 Go 标准库的 {{template}} 动作。它不解析变量、不调用方法,只做两件事:按路径加载子模板文件,并把传入的数据作为上下文执行渲染。
常见错误是以为路径支持相对语法(比如 {{template "../_form.tpl" .}}),实际 Beego 的模板路径始终以 views/ 为根目录,不支持 ../ 回退。路径必须写全,例如:
-
{{template "zones/_form.tpl" .}}—— 正确,从views/zones/_form.tpl加载 -
{{template "_form.tpl" .}}—— 仅当该文件在views/根目录下才有效 -
{{template "base/header.tpl" .}}—— 跨子目录没问题,但路径不能省略
命名建议加下划线前缀(如 _form.tpl),不是技术强制,而是避免被 IDE 当作主模板误点、也方便 grep 过滤。
传递数据时,用 map 或结构体比用 . 更可控
直接写 {{template "xxx.tpl" .}} 看似简单,但容易导致子模板意外访问到父模板不需要的字段(比如 .User.Token 泄露)。尤其当多个 partial 共享同一上下文时,字段冲突风险上升。
更稳妥的做法是在 Controller 中构造明确的数据结构:
this.Data["FormCtx"] = map[string]interface{}{
"Zone": zone,
"Errors": errors,
"Title": "Create Zone",
}
this.TplName = "zones/new.tpl"
然后在主模板中:
{{template "zones/_form.tpl" .FormCtx}}
这样 _form.tpl 里只能访问 .Zone、.Errors、.Title,不会误读 .Data 或其他 Controller 级字段。Go 模板会自动将 map 展开为字段可读上下文。
Layout 和 partial 不是替代关系,是分层协作
有人混淆 this.Layout 和 {{template}}:前者控制整页骨架(header/footer/content 区域划分),后者控制 content 内部的片段复用。两者可以并存,且常一起用。
典型组合是:
- Controller 设置
this.Layout = "base.html"和this.TplName = "user/edit.tpl" -
base.html中包含{{.LayoutContent}},用于插入user/edit.tpl渲染结果 -
user/edit.tpl内部再用{{template "user/_form.tpl" .FormCtx}}拆解表单逻辑
注意:.LayoutContent 是 Beego 自动注入的变量名,不可改;而 LayoutSections 是额外插槽机制,比如 {{.Header}}、{{.Footer}},需在 Controller 中显式赋值路径字符串,不能传结构体或 map。
缓存与热更新:修改 partial 后要重启或手动清理
Beego 默认会缓存所有模板文件(包括被 {{template}} 引用的 partial),开发阶段改了 _form.tpl 却没生效?大概率是缓存没刷新。
解决方式有两个:
- 启动时加参数
-runmode=dev,Beego 会监听文件变化并自动 reload(生产环境禁用) - 手动调用
beego.BConfig.WebConfig.TemplateLeft = "{{"等配置不影响缓存,真正起效的是清空beego.TemplateCache—— 但无公开 API,最稳做法仍是重启进程
这点容易被忽略:Layout 文件(如 base.html)和 partial(如 _form.tpl)都受同一套缓存控制,改任意一个,都要触发重载。别只盯着主模板文件。


















