revel模板传参需用render传命名参数或map/结构体,变量须导出;输出用{{.x}}自动转义,遍历前须判空;range双变量解构需dict或map传参,自定义变量名必须加$前缀。

在Revel框架中向HTML模板传递数据时,必须明确Render方法如何接收参数、模板中如何引用这些值,否则会出现变量未定义或渲染为空的问题。
控制器中调用Render传参的两种写法
方法一:直接传入多个命名参数(推荐)
在控制器action中写:c.Render("title", "首页", "users", users, "count", len(users))。Revel会自动将每对参数转为键值对存入c.RenderArgs,模板中可直接用{{.title}}、{{.users}}访问。
方法二:传入结构体或map
调用c.Render(map[string]interface{}{"title": "首页", "data": data})。此时模板根上下文就是该map,必须用{{.title}}访问,不能省略点号;若传结构体,则字段必须首字母大写且有导出权限。
【传参时若使用未导出字段(小写开头)或nil切片,模板中对应变量将为空且不报错】
模板中安全输出变量的三类写法
基础输出:{{.title}} 直接渲染字符串,无转义。适用于已知安全内容,如页面标题。
HTML转义输出:{{.content | safe}} → 错误写法。safe不是内置函数,Revel默认不注册该函数。正确做法是用{{.content}}(自动HTML转义),或改用{{.RawContent}}(需控制器提前赋值为template.HTML类型)。
条件判空后输出:
{{if .items}}
{{range .items}}
{{end}}
{{else}}
暂无数据
{{end}}
这一步必须加{{if .items}},否则当.items为nil时模板执行会panic。
遍历切片并同时传递索引与元素给子模板
第一步:在控制器中确保传入的是非nil切片
func (c App) List() revel.Result {
templates := []string{"header", "main", "footer"}
return c.Render(templates)
}
第二步:主模板中用双变量range解构
{{if .}}
{{range $i, $t := .}}
{{template "item.html" (dict "Index" $i "Value" $t)}}
{{end}}
{{end}}
第三步:子模板item.html中接收并使用
注意:dict函数需在app/init.go中手动注册,否则此处会报错“function \"dict\" not defined”。
第四步:若未注册dict,改用map字面量(Go 1.18 +支持)
{{template "item.html" (map "Index" $i "Value" $t)}}
避免变量名冲突的关键细节
模板中不要用和控制器传入参数同名的range变量,例如控制器传了{{.Index}},就不要再写{{range $Index, $Item := .List}}——否则内层的$Index会覆盖外层的.Index值。
所有自定义变量名前必须加$,如{{$i}},否则在嵌套{{with}}或{{range}}块中会被静默覆盖,导致后续逻辑读到错误值。
如果子模板需要同时访问当前元素和全局参数(如.PageTitle),必须显式传入:{{template "sub.html" (dict "Item" $t "Title" $.PageTitle)}},其中$.表示根上下文。











