SSR
服务端渲染(Server-Side Rendering,简称SSR)是指在服务器上生成完整的HTML页面,并将其发送到客户端的过程。
在这种模式下,当客户端(通常是浏览器)请求一个页面时,服务器会根据请求生成HTML内容,并将生成的完整页面返回给客户端。客户端接收到HTML后可以立即显示,而无需再通过JavaScript来动态生成页面内容。
响应HTML
Gin可使用LoadHTMLGlob或LoadHTMLFiles方法加载模板,并通过HTML方法响应:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/**/*")
r.GET("/", func(c *gin.Context) {
c.HTML(200, "index.html", gin.H{
"title": "This is a title",
"message": "Welcome",
})
})
r.Run(":8080")
}
路径问题
由于项目最终都要打包,为了避免出现找不到模板的问题,可在模板中使用define定义模板名称,以此固定模板:
- templates/home/index.html
- templates/home/list.html
- templates/user/list.html
- main.go
{{ define "home-index" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .title }}</title>
</head>
<body>
{{ .title }}
</body>
</html>
{{ end }}
{{ define "home-list" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .title }}</title>
</head>
<body>
{{ .title }}
</body>
</html>
{{ end }}
{{ define "user-list" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .title }}</title>
</head>
<body>
{{ .title }}
</body>
</html>
{{ end }}
r.GET("/home", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "home-index", gin.H{
"title": "Home Index",
})
})
r.GET("/list", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "home-list", gin.H{
"title": "Home List",
})
})
r.GET("/user/list", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "user-list", gin.H{
"title": "User List",
})
})
列表渲染
模板中可通过循环进行列渲染:
- main.go
- templates/user/list.html
type Student struct {
Id int32
Name string
Age uint8
Score float32
}
var students = []Student{
{
Id: 1,
Name: "Mike",
Age: 12,
Score: 98.5,
},
{
Id: 2,
Name: "Tom",
Age: 15,
Score: 89,
},
}
r.GET("/user/list", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "user-list", gin.H{
"title": "User List",
"students": students,
})
})
{{ define "user-list" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .title }}</title>
</head>
<body>
{{ .title }}
<table border="1" style="border-collapse: collapse;">
<thead>
<th>ID</th>
<th>Name</th>
<th>Age</th>
<th>Score</th>
<th>Level</th>
</thead>
<tbody>
<!-- 循环渲染 -->
{{ range $index, $s := .students }}
<tr>
<td>{{ $s.Id }}</td>
<td>{{ $s.Name }}</td>
<td>{{ $s.Age }}</td>
<td>{{ $s.Score }}</td>
<td>
<!-- if else -->
{{ if (ge $s.Score 90.0) }}
A
{{ else }}
B
{{ end }}
</td>
</tr>
{{ end }}
</tbody>
<tfoot></tfoot>
</table>
</body>
</html>
{{ end }}
模板嵌套
一个模板中可通过template关键字嵌入其它模板并传递数据,以此分离模板便于维护:
- list.html
- thead.html
- tbody.html
- trow.html
- tfoot.html
{{ define "user-list" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .title }}</title>
</head>
<body>
{{ .title }}
<table border="1" style="border-collapse: collapse;">
{{ template "thead.html" }}
<!-- 嵌入tbbody.html 并传递students数据 -->
{{ template "tbody.html" .students }}
{{ template "tfoot.html" }}
</table>
</body>
</html>
{{ end }}
<thead>
<th>ID</th>
<th>Name</th>
<th>Age</th>
<th>Score</th>
<th>Level</th>
</thead>
<tbody>
{{ range $index, $s := . }}
{{ template "trow.html" $s }}
{{ end }}
</tbody>
<tr>
<td>{{ .Id }}</td>
<td>{{ .Name }}</td>
<td>{{ .Age }}</td>
<td>{{ .Score }}</td>
<td>
{{ if (ge .Score 90.0) }}
A
{{ else }}
B
{{ end }}
</td>
</tr>
<tfoot></tfoot>
静态目录
可通过r.Static方法指定静态目录访问路径,以便访问静态资源:
r.Static("/static", "./static")
此时如果访问/static/data.json,将会去当目录下的static目录找data.json文件。