Revel模板中嵌入子模板必须用{{render "Path/Name"}}语法,路径须为从app/views/起的完整相对路径(不含.html后缀),且需显式传参;子模板作用域独立,不继承父模板局部变量,禁止循环引用。

Revel模板中用 render 函数嵌入子模板
Revel 的模板系统不支持类似 Go 标准库 template.ParseFiles 那样的 {{template "name" .}} 语法,而是统一用 render 函数加载并执行子模板。它会自动查找 app/views/ 下对应路径的文件,并传入当前上下文(或显式传参)。
比如你在 app/views/App/Index.html 中想嵌入一个通用页脚:
{{render "App/Footer.html"}}Revel 会按约定路径查找 app/views/App/Footer.html,并把当前模板的 .(即 controller.RenderArgs)传进去。如果子模板需要额外数据,可以显式传参:
{{render "User/Avatar.html" .CurrentUser}}子模板路径必须带目录前缀,不能省略
Revel 模板解析器对路径敏感,Footer.html 和 App/Footer.html 是完全不同的路径。即使子模板和当前模板在同一目录下,也不能写成 {{render "Footer.html"}} —— 这会导致 template: "Footer.html": no such template 错误。
立即学习“go语言免费学习笔记(深入)”;
正确做法是始终使用完整相对路径(从 app/views/ 开始,不含 .html 后缀):
-
{{render "App/Header.html"}}✅ -
{{render "Shared/Alert.html"}}✅ -
{{render "Footer.html"}}❌(找不到) -
{{render "/App/Footer.html"}}❌(开头斜杠会被忽略或报错)
子模板里不能直接访问父模板局部变量
Revel 的 render 是独立作用域:子模板接收的是传入的参数值(如 . 或 .CurrentUser),不会自动继承父模板中用 {{with}}、{{range}} 或 {{.Foo = "bar"}} 定义的局部变量。
常见误写:
{{with .User}}
{{render "User/ProfileCard.html"}} <!-- ProfileCard.html 里访问 .Name 会 panic --}}
{{end}}正确方式是显式传递:
{{with .User}}
{{render "User/ProfileCard.html" .}}
{{end}}或者更明确地命名:
{{render "User/ProfileCard.html" dict "user" .User "showEdit" true}}避免循环引用和重复初始化逻辑
Revel 模板在渲染时是同步展开的,如果 A 模板 render B,B 又 render A,就会触发栈溢出(runtime: goroutine stack exceeds 1000000000-byte limit)。这不像前端框架有懒加载或虚拟 DOM 缓解机制。
另外要注意:子模板中调用 controller.Render 相关函数(如 {{flash}}、{{xsrf}})仍有效,但若子模板反复被多个父模板调用,其中的初始化逻辑(比如 {{if .CurrentSession}}...)应尽量无副作用。
真正容易被忽略的是:Revel 不缓存子模板的编译结果(除非你手动启用 revel.TemplateFuncs 注册全局函数替代部分 render 场景),高频嵌套可能轻微拖慢首屏。如果某个子片段纯静态或仅依赖少量固定字段,考虑改用自定义模板函数封装,而非每次都 render 文件。


















