Gin 入门笔记(三)HTML 模板与静态文件服务
一、 模板配置
模板配置分为两种情况
1. 全部模板放在一个目录
在 templates 里放置所有模板,再在 main.go 里使用r.LoadHTMLGlob("templates/*")
即可
2. 模板放在不同目录
这里以下面的结构为例子
1 | test |
在前端页面的开头加上{{ define "front/index.html" }}
,并在结尾加上{{ end }}
1 | {{ define "front/index.html" }} |
后端类似
1 | {{ define "back/index.html" }} |
这相当与给模板起一个名称,define
和 end
是成对出现的
回到 main.go ,加载模板的语句要变化,使用两个星号表示一层目录,并分别配置前后端路由
1 | package main |
当然,也可以选择用r.LoadHTMLFiles()
来引用单个模板文件
二、模板语法
有关模板的语法很多
1、输出数据
模板语法都包含在{{` 和`}}
中间,其中{{.}}
中的点表示当前对象
当我们传入一个结构体对象时,我们可以根据.
来访问结构体对于的字段
例如,在 main.go 中创建一个 UserInfo 类型
1 | type UserInfo struct { |
在前端页面中添加对应的字段
1 | <p>{{.user.Name}}</p> |
实例化一个 user ,并传递
1 | user := UserInfo{ |
2、解构结构体
在上面,我们使用这一段
1 | <p>{{.user.Name}}</p> |
使用 with 可以解构结构体,简化这一步骤
1 | {{with .user}} |
3、注释
1 | {{/* a comment */}} |
注释不能嵌套,并且必须紧贴分界符始止
4、变量
可以在模板中声明变量,来保存传入模板的数据或其他语句生成的结果,方法如下:
1 | <h4>{{$t := .title}}</h4> |
5、移除空格
有时候我们在使用模板语法是时候会不可避免地引入空格或换行符,这样模板最终渲染出来的内容可能就和我们想的不一样,这个时候就可以使用````去除模板内容右侧的所有空白符号
1 | {{- .Name -}} |
6、比较大小
- eq 等于 ( == )
- ne 不等于 ( != )
- lt 小于 ( < )
- le 小于等于 ( <= )
- gt 大于 ( > )
- ge 大于等于 ( >= )
注意,使用 eq A B
来比较 A
B
是否相等,而不是A eq B
比较大小常和下面的判断一起使用
7、条件判断
- if-else-end 结构
1 | {{if gt .score 60}} |
- if-else if-else-end 结构
1 | {{if gt .score 90}} |
8、遍历
Go的模板语法中使用 range 关键字进行遍历,有以下两种写法,其中 obj 必须是数组、切片、字典或者通道
1 | {{range $key,$value := .obj}} |
1 | {{range $key,$value := .obj}} |
如果 obj 为空,则会返回"没有数据"
例:
1 | r.GET("/front", func(c *gin.Context) { |
9、函数
函数有预定义的,还可以自行定义,但其实预定义的基本没什么用,所以一般都用自己定义的函数
-
预定义函数
and
函数返回它的第一个 empty 参数或者最后一个参数;
就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
返回第一个非 empty 参数或者最后一个参数;
亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
返回它的单个参数的布尔值的否定
len
返回它的参数的整数类型长度
index
执行结果为第一个参数以剩下的参数为索引/键指向的值;
如"index x 1 2 3"返回 x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
print
即 fmt.Sprint
printf
即 fmt.Sprintf
println
即 fmt.Sprintln
html
返回与其参数的文本表示形式等效的转义 HTML。
这个函数在 html/template 中不可用。
urlquery
以适合嵌入到网址查询中的形式返回其参数的文本表示的转义值。
这个函数在 html/template 中不可用。
js
返回与其参数的文本表示形式等效的转义 JavaScript。
call
执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函
数的参数;
如"call .X.Y 1 2"等价于 go 语言里的 dot.X.Y(1, 2);
其中 Y 是函数类型的字段或者字典的值,或者其他类似情况;
call 的第一个参数的执行结果必须是函数类型的值(和预定义函数如 print 明显不同);
该函数类型值必须有 1 到 2 个返回值,如果有 2 个则后一个必须是 error 接口类型;
如果有 2 个返回值的方法返回的 error 非 nil,模板执行会中断并返回给调用模板执行者
该错误; -
自定义函数
例如,我们在后台有一个 UNIX 时间戳,希望在渲染模板时自动转换常用的时间格式
1 | r.GET("/back", func(c *gin.Context) { |
首先需要自己在 main.go 里先写一个实现这一功能的函数
1 | func Unix2Time(timestamp int)string{ |
然后在加载模板上方,创建引擎下方通过r.SetFuncMap()
注册自定义模板函数
1 | r.SetFuncMap(template.FuncMap{ |
现在,在模板中就可以调用函数了
1 | {{Unix2Time .date}} |
10、模板嵌套
比如,现在需要给前端和后端设计一个公共的标题
在 templates 中新建 public/page_header.html
1 | {{ define "public/page_header.html" }} |
使用{{template "public/page_header.html" .}}
引入**(注意末尾的点)**
当然,嵌套同一个模板并不表示会显示相同的内容,比如我们稍加修改,就能分别展示前端和后端的标题
三、静态文件服务
当我们渲染的 HTML 文件中引用了静态文件时(如css、js、图片等),我们需要使用r.Static
配置静态 web 服务
1 | func main() { |
1 | <link rel="stylesheet" href="/static/css/base.css" /> |
注意在模板里引用时 static 前面的斜杠不要漏