Revel模板中用range遍历切片需双变量绑定:{{range $i, $user := .Users}},$i为索引,$user为元素;传参子模板用$template "path" $user;.Users须非nil,建议初始化为空切片;分页用{{url "Route" "page" 2}}保留原查询参数。

用 range 遍历数据切片并安全传参给子模板
Revel 模板里渲染列表,核心就是 range。但直接写 {{range .Users}} 只能拿到当前元素,没法传索引或额外上下文——比如要给每行加序号、绑定唯一 id、或根据位置决定样式,就必须显式解构。
正确写法是双变量绑定,且变量名必须带 $ 前缀:
-
{{range $i, $user := .Users}}——$i是 int 类型索引(从 0 开始),$user是当前结构体实例 -
{{template "user/item.html" $user}}或{{template "user/item.html" $i}},按需传入子模板 - 不加
$(如i, user)会导致变量作用域污染:若控制器也传了.i字段,就会被覆盖,且无任何报错提示 - 如果
.Users是nil,range会静默跳过,不 panic,但页面空白——务必在控制器里确保它至少是空切片:c.RenderArgs["Users"] = []*models.User{}
在列表项模板中复用 field 渲染编辑表单
列表页常带「编辑」操作,点击后展开行内表单。这时不能每个字段都手写 name、value 和错误类,得靠 field 函数自动绑定。
假设每行对应一个 User,ID 为 $user.ID,编辑字段是 Nickname:
- 在子模板
user/item.html中写:{{with $field := field (printf "users[%d].Nickname" $i) .}}{{input $field}}{{end}} -
printf构造带索引的字段名,服务端接收时就能映射到数组结构;input是 Revel 内置函数,自动生成type="text"+name+value+class="error"(有错时) - 注意:控制器方法参数必须匹配这个命名,例如
Update方法要接收users []struct{Nickname string}或逐个字段如nickname0 string, nickname1 string,否则绑定失败,$field.Value为空 - 如果没调用
c.Validation.Error("users[0].Nickname"),$field.Error就一直是空字符串,错误提示不会出现
分页链接生成别硬拼 URL,用 url 模板函数
列表页几乎必带分页。手写 /users?page=2 看似简单,但容易漏掉已有查询参数(如 ?q=admin),导致筛选失效。
- Revel 提供
url函数,自动合并路径与查询参数:{{url "UserController.List" "page" 2}} - 它会读取当前请求的
c.Params.Query,保留q、sort等原有参数,只替换page值 - 如果路由定义是
GET /users UserController.List,那url生成的就是/users?page=2&q=admin - 错误写法:
/users?page={{add .Page 1}}—— 丢失其他参数,且add不是 Revel 内置函数(需自定义注册),直接用会渲染为空
避免列表页因数据缺失导致模板崩溃的三个细节
列表页最怕「看着正常,点开就 500」。多数问题出在模板上下文没对齐,而不是逻辑本身。
- 控制器里传的是
*[]models.User(指针切片),模板里写{{range .Users}}会 panic;必须传[]*models.User或[]models.User(值切片) -
{{.Users.0.Nickname}}这种链式访问,只要中间任一环节为nil(比如.Users是空切片),就会 panic;改用{{with .Users}}{{if .}}{{index . 0}}{{end}}{{end}}更安全 - 如果列表项需要调用方法(如
$user.FullName()),确保该方法在模板上下文中可见:Go 结构体方法必须是导出的(首字母大写),且接收者不能是值类型指针混用(如func (u *User) FullName()不能在$user是值类型时调用)











