Revel模板变量传递必须通过Render注入且严格遵循约定:命名参数最稳妥,字段须导出、大小写匹配,range遍历前需判空并用$i索引,子模板不继承局部变量。

Revel 模板变量传递不是“写进去就能用”,而是严格依赖 Render 的参数注入方式和模板中 {{.x}} 的访问约定;传错类型、字段未导出、大小写不匹配,都会导致渲染为空或 panic。
Render 传命名参数是最稳的写法
控制器里直接传键值对,Revel 自动转成小驼峰变量名,模板里用 {{.title}}、{{.users}} 就能取到:
-
c.Render("title", "首页", "users", users, "count", len(users))→ 模板中{{.title}}输出“首页” - 字段名自动转小驼峰:传
"UserName",模板里必须写{{.userName}},不能写{{.UserName}} - 避免混用:不要同时
c.Render("user", u)和c.RenderArgs["user"] = u,后者会覆盖前者
传结构体必须确保字段导出且首字母大写
如果用结构体传参,Go 的反射机制要求字段可导出,否则模板完全看不到:
- 正确:
type User struct { Name string; Email string }→ 模板中{{.user.Name}} - 错误:
type User struct { name string }→{{.user.name}}渲染为空,无报错 - 传结构体时,模板根上下文就是该结构体实例,所以
{{.Name}}可以直接访问(前提是c.Render("user", u)) - 别用
map[string]interface{}包一层再传——类型擦除后大小写更难控制,{{.Users}}可能突然变成{{.users}}
range 遍历切片前必须判空,索引变量必须加 $ 前缀
nil 切片直接 {{range .items}} 会 panic;索引变量不加 $ 会在嵌套模板里被覆盖:
- 安全写法:
{{if .items}}{{range $i, $item := .items}}...{{end}}{{else}}暂无数据{{end}} -
$i是 int 类型索引,$item是当前元素;写成i, item(不加$)会导致外层同名变量被静默覆盖 - 传给子模板时,显式传
{{template "item.html" $i}}或{{template "item.html" $item}},不能依赖.自动切换 - 如果子模板需要同时拿到索引和元素,得在父模板里先
{{with $item}}或拼成 map 传入
子模板 render 不继承父模板局部变量
{{render "App/Header.html"}} 会把当前 RenderArgs 全量传入,但不会带进 {{with}} 或 {{range}} 里定义的临时变量:
- 路径必须完整:写
{{render "App/Header.html"}}✅,写{{render "Header.html"}}❌(找不到) - 想只传部分数据,显式写
{{render "User/Avatar.html" .CurrentUser}},子模板里用{{.Name}}访问 - 子模板作用域独立,
{{.flash.success}}这类全局注入项仍可用,但{{.foo = "bar"}}这种赋值在子模板里不可见 - 禁止循环引用:A 模板
renderB,B 再renderA,会触发模板解析死循环
最常被忽略的是字段导出规则和 $ 前缀——它们不出错,但会让变量永远取不到;而 Render 和 RenderTemplate 对 . 上下文的处理差异,也容易在迁移时悄悄破坏渲染逻辑。


















