官方文档:https://gin-gonic.com/zh-cn/docs/
注:强烈建议没用过Gin的读者先阅读第一节:第一个Gin应用。
目录
一、简单渲染
以"03HTML渲染"为根目录,创建如下目录结构:
bash
├─demo01
│ │ main.go
│ └─templates
│ index.html
├─demo02
│ │ main.go
│ └─templates
│ ├─posts
│ │ index.html
│ └─users
│ index.html
├─demo03
│ file1.html
│ file2.html
│ main.go
├─demo04
│ │ main.go
│ └─templates
│ index.html
└─demo05
│ main.go
└─templates
raw.html
进入到demo01,填充代码:
main.go
go
package main
import (
"net/http" // 导入 HTTP 状态码和服务功能
"github.com/gin-gonic/gin" // 导入 Gin 框架
)
func main() {
router := gin.Default() // 创建一个默认的 Gin 路由器,带有默认的中间件(如日志和恢复)
// 加载所有位于 /templates 目录下的 HTML 文件,支持通配符(如 *.html)
router.LoadHTMLGlob("templates/*")
// 使用 LoadHTMLFiles 可以加载指定的多个文件
// router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
// 设置一个 GET 路由,当用户访问 /index 时,返回 HTML 页面
router.GET("/index", func(c *gin.Context) {
// 使用 HTML 渲染函数,HTTP 状态码 200 (http.StatusOK),
// 渲染 "index.html" 文件,并传递数据(键值对形式)供模板使用
c.HTML(http.StatusOK, "index.html", gin.H{
"title": "Main website", // 传递 "title" 变量到模板
})
})
// 运行应用程序,并监听在端口 8080 上
router.Run(":8080")
}
index.html
html
<html>
<h1>
{{ .title }} <!-- 这里是模板占位符,将被渲染时替换为 title 变量的值 -->
</h1>
</html>
LoadHTMLGlob()
:用于加载模板文件的函数。LoadHTMLGlob("../templates/*")
表示加载 .../templates 目录下的所有 HTML 文件。它支持通配符,常用于一次性加载多个模板。
LoadHTMLFiles()
:和 LoadHTMLGlob() 类似,但它不使用通配符,而是明确列出要加载的模板文件。可以根据需要使用该函数加载特定的模板文件。
c.HTML(http.StatusOK, "index.html", gin.H{"title": "Main website"})
:渲染 index.html 模板,并将 title 变量传递给模板,值为 "Main website"。在模板文件中,{``{ .title }}
会被渲染为传递进来的 title 值。
注意 :Gin 的模板引擎支持多种文件扩展名,常见的 .html
文件扩展名并不是必须的,比如你可以将模板文件命名为 .tmpl
,模板引擎同样能够识别和渲染这些文件。但个人建议仍使用.html,因为IDE都能对.html提供代码高亮和补全。
效果 :
二、使用不同目录下名称相同的模板
进入到demo02,填充代码:
main.go
go
package main
import (
"net/http" // 导入 HTTP 状态码和服务功能
"github.com/gin-gonic/gin" // 导入 Gin 框架
)
func main() {
router := gin.Default() // 创建一个默认的 Gin 路由器,带有默认中间件(如日志和恢复)
// 加载 templates 目录下所有子目录的所有模板文件
router.LoadHTMLGlob("templates/**/*")
// 定义一个 GET 路由,处理 /posts/index
router.GET("/posts/index", func(c *gin.Context) {
// 渲染 posts/index.html 模板,并传递数据
c.HTML(http.StatusOK, "posts/index.html", gin.H{
"title": "Posts", // 传递标题
})
})
// 定义另一个 GET 路由,处理 /users/index
router.GET("/users/index", func(c *gin.Context) {
// 渲染 users/index.html 模板,并传递数据
c.HTML(http.StatusOK, "users/index.html", gin.H{
"title": "Users", // 传递标题
})
})
// 启动 HTTP 服务器,监听 8080 端口
router.Run(":8080")
}
posts/index.html
html
{{ define "posts/index.html" }} <!-- 定义一个名为 "posts/index.html" 的模板块 -->
<html>
<h1>
{{ .title }} <!-- 这里会被传递进来的标题替换 -->
</h1>
<p>Using posts/index.html</p> <!-- 说明当前使用的是哪个模板 -->
</html>
{{ end }} <!-- 结束模板块定义 -->
users/index.html
html
{{ define "users/index.html" }} <!-- 定义一个名为 "users/index.html" 的模板块 -->
<html>
<h1>
{{ .title }} <!-- 这里会被传递进来的标题替换 -->
</h1>
<p>Using users/index.html</p> <!-- 说明当前使用的是哪个模板 -->
</html>
{{ end }} <!-- 结束模板块定义 -->
模板定义:每个模板都使用 {``{ define "模板名称" }}
和 {``{ end }}
包裹,定义了一个可重用的模板块。在渲染时,通过指定模板的完整名称来选择要渲染的具体模板。
这使得在不同目录中存在同名模板时(比如这里都有index.html) ,可以准确指定使用哪个模板。当然,使用LoadHTMLFiles()
可以不用定义模板块,也能达到相同的效果,就是要指定具体文件路径而已。相对来说,LoadHTMLGlob()
使用更方便,不管templates下有多少个模板,调用语句都是一样的。
效果 :
三、自定义模板渲染器
进入到demo03,填充代码:
main.go
go
package main
import (
"html/template" // 导入 HTML 模板包
"net/http"
"github.com/gin-gonic/gin" // 导入 Gin 框架
)
func main() {
router := gin.Default()
// 加载 file1.html 和 file2.html 模板文件
html := template.Must(template.ParseFiles("file1.html", "file2.html"))
// 设置自定义的 HTML 模板渲染器
router.SetHTMLTemplate(html)
// 定义一个路由,当用户访问 /file1 时,返回 file1.html 页面
router.GET("/file1", func(c *gin.Context) {
c.HTML(http.StatusOK, "file1.html", gin.H{
"title": "Hello, World", // 传递 "title" 变量到模板
})
})
// 定义另一个路由,当用户访问 /file2 时,返回 file2.html 页面
router.GET("/file2", func(c *gin.Context) {
c.HTML(http.StatusOK, "file2.html", gin.H{
"title": "Hello, World", // 传递 "title" 变量到模板
})
})
// 启动 Gin 服务器,监听在 8080 端口
router.Run(":8080")
}
file1.html
html
<!DOCTYPE html>
<html>
<head>
<title>{{ .title }} - File 1</title>
</head>
<body>
<h1>{{ .title }} from File 1</h1>
<p>This content is rendered from file1.html.</p>
</body>
</html>
file2.html
html
<!DOCTYPE html>
<html>
<head>
<title>{{ .title }} - File 2</title>
</head>
<body>
<h1>{{ .title }} from File 2</h1>
<p>This content is rendered from file2.html.</p>
</body>
</html>
效果 :
到目前为止,我们已经学了三种模板加载方法:
1.定义模板名,用LoadHTMLGlob()
2.不定义模板名,用LoadHTMLFiles()
3.不用模板目录,用template.Must()
在真实开发中,团队和项目的性质通常会影响选择的方式。常见的倾向包括:
中大型项目:往往会选择 1,因为它能保持项目结构的整洁,并且方便管理多个模板。
小型项目:可能会倾向于 2,因为它提供了更大的灵活性和可控性。
原型开发或快速迭代:通常会选择 3,以便于快速验证和调整。
四、自定义分隔符
进入到demo04,填充代码:
main.go
go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 设置自定义的分隔符
r.Delims("{[{", "}]}")
// 加载指定路径下的 HTML 模板
r.LoadHTMLGlob("templates/*")
// 定义一个路由,当用户访问 /index 时,返回 index.html 页面
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"title": "Custom Delimiter Example", // 传递 "title" 变量到模板
})
})
// 启动 Gin 服务器,监听在 8080 端口
r.Run(":8080")
}
index.html
html
<!DOCTYPE html>
<html>
<head>
<title>{[{ .title }]}</title>
</head>
<body>
<h1>{[{ .title }]}</h1>
<p>Welcome to the page with custom delimiters!</p>
</body>
</html>
效果 :
五、自定义模板函数
进入到demo05,填充代码:
main.go
go
package main
import (
"fmt"
"html/template"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// 自定义函数:将时间格式化为指定格式
func formatAsDate(t time.Time) string {
year, month, day := t.Date()
return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}
func main() {
router := gin.Default()
router.Delims("{[{", "}]}") // 设置自定义分隔符
// 注册自定义函数
router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, // 将 formatAsDate 函数注册为模板函数
})
// 加载 HTML 模板文件
router.LoadHTMLFiles("templates/raw.html")
// 定义路由,当用户访问 /raw 时,返回 raw.html 模板
router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.html", map[string]interface{}{
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), // 传递当前时间到模板
})
})
// 启动 Gin 服务器,监听在 8080 端口
router.Run(":8080")
}
raw.html
html
Date: {[{.now | formatAsDate}]}
注意 :
1.FuncMap()
中的key和value可以不同。
2.html中调用的函数名是FuncMap()
中的key ,不是value!也就是说,value的值可以随便取,不影响html调用。
3.SetFuncMap
必须在 LoadHTMLFiles
之前调用!
效果 :
六、总结
在使用 Gin 框架进行 HTML 渲染时,可以通过 LoadHTMLGlob() 或 LoadHTMLFiles() 方法加载模板文件。LoadHTMLGlob() 支持使用通配符,适合批量加载多个模板,而 LoadHTMLFiles() 允许精确加载特定的模板文件。通过在模板中定义结构,可以避免不同目录中同名模板的冲突,确保在渲染时通过完整名称来选择正确的模板。自定义模板渲染器和函数映射(使用 SetFuncMap)可以扩展模板功能,如格式化日期。使用自定义分隔符可改变模板中变量的标识符。