HTML 模板渲染
下面是使用 Gin 框架在 Go 语言中进行 HTML 模板渲染的四个示例。每个示例都包含了必要的注释来解释代码的作用。
示例1:基本模板渲染
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 加载HTML模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个简单的路由处理函数,渲染HTML模板
r.GET("/greet", func(c *gin.Context) {
// 渲染 "greet.html" 模板,并传递一些数据给模板
c.HTML(http.StatusOK, "greet.html", gin.H{
"title": "Greeting Page",
"message": "Hello, welcome to the Greeting page!",
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
templates/greet.html
文件内容如下:
html
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
</head>
<body>
<h1>{{.message}}</h1>
</body>
</html>
示例2:带有参数的模板渲染
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 加载HTML模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个带参数的路由处理函数,渲染HTML模板
r.GET("/user/:name", func(c *gin.Context) {
// 获取URL路径中的参数
userName := c.Param("name")
// 渲染 "profile.html" 模板,并传递用户名称给模板
c.HTML(http.StatusOK, "profile.html", gin.H{
"title": "User Profile",
"name": userName,
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
templates/profile.html
文件内容如下:
html
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
</head>
<body>
<h1>Welcome {{.name}}!</h1>
</body>
</html>
示例3:多模板文件渲染
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 加载HTML模板文件夹下的所有模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个路由处理函数,渲染多个模板文件
r.GET("/dashboard", func(c *gin.Context) {
// 渲染 "header.html" 和 "content.html" 模板文件
c.HTML(http.StatusOK, "header", gin.H{
"title": "Dashboard",
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
templates/dashboard.html
文件内容如下:
html
{{define "header"}}
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
</head>
<body>
<header>
<h1>Header Section</h1>
</header>
{{end}}
{{define "content"}}
<main>
<p>This is the content section of the dashboard.</p>
</main>
{{end}}
{{define "footer"}}
<footer>
<p>Footer Section</p>
</footer>
</body>
</html>
{{end}}
请注意,dashboard.html
中定义了三个模板部分(header
, content
, footer
),它们可以在主模板中被调用。
示例4:模板继承和局部模板
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 加载HTML模板文件夹下的所有模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个路由处理函数,渲染主模板并包含局部模板
r.GET("/blog", func(c *gin.Context) {
// 渲染 "base.html" 主模板,并传递数据给模板
c.HTML(http.StatusOK, "base.html", gin.H{
"title": "Blog Page",
"posts": []string{"Post 1", "Post 2", "Post 3"},
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
templates/base.html
文件内容如下:
html
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
</head>
<body>
<header>
<h1>{{.title}}</h1>
</header>
<div id="content">
{{template "postList" .}}
</div>
</body>
</html>
templates/postlist.html
文件内容如下:
html
{{define "postList"}}
<ul>
{{range .posts}}
<li>{{.}}</li>
{{end}}
</ul>
{{end}}
在这个例子中,base.html
是主模板,而 postlist.html
包含了一个局部模板,它会在主模板中被引用。通过这种方式,可以实现模板的复用和继承,从而简化页面结构和维护工作。
gin 模板基本语法
Gin 框架使用 Go 的标准库 html/template
来处理模板,因此 Gin 模板的基本语法与 Go 的模板语法相同。以下是 Gin 模板的一些基本语法和特性:
变量插值
在模板中插入变量的值,可以使用双大括号 {``{}}
包围变量名。
html
<p>Hello, {{.Name}}!</p>
.
表示当前上下文的数据结构。- 如果传递给模板的是一个 map 或 struct,则可以通过点符号访问其字段或键。
当然,下面是一个使用 Gin 框架和 Go 的 html/template
进行变量插值的简单示例。这个例子展示了如何将数据从 Go 代码传递到 HTML 模板,并在模板中正确显示这些数据。
示例:变量插值
Go 文件(main.go
)
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"time"
)
// 定义一个结构体来表示用户信息
type User struct {
Name string
Email string
JoinDate time.Time
}
func main() {
// 创建默认的 Gin 路由器
r := gin.Default()
// 加载HTML模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个路由处理函数,渲染HTML模板并传递用户数据
r.GET("/user", func(c *gin.Context) {
// 创建一个用户实例
user := User{
Name: "Alice",
Email: "alice@example.com",
JoinDate: time.Now(),
}
// 渲染 "user.html" 模板,并传递用户数据给模板
c.HTML(http.StatusOK, "user.html", gin.H{
"title": "User Profile",
"user": user,
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
HTML 模板文件(templates/user.html
)
html
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title> <!-- 使用 .title 变量设置页面标题 -->
</head>
<body>
<h1>User Profile</h1>
<!-- 使用 .user.Name 和 .user.Email 插入用户名称和电子邮件 -->
<p>Name: {{.user.Name}}</p>
<p>Email: {{.user.Email}}</p>
<!-- 格式化并插入用户的加入日期 -->
<p>Joined on: {{.user.JoinDate.Format "2006-01-02"}}</p>
<!-- 如果你想确保输出是安全的HTML(例如包含标签),可以使用 template.HTML 类型 -->
</body>
</html>
代码注释解释
-
Go 文件 (
main.go
)User
结构体定义了用户信息的字段。r.LoadHTMLGlob("templates/*")
用于加载所有位于templates/
目录下的HTML模板文件。- 在
/user
路由处理函数中,创建了一个User
实例,并通过c.HTML()
方法将此实例以及页面标题一起传递给模板。 gin.H{}
是一个快捷方式来创建一个 map,用于存储传递给模板的数据。
-
HTML 模板文件 (
templates/user.html
)- 使用
{``{.title}}
来插入来自 Go 代码中的页面标题。 - 使用
{``{.user.Name}}
和{``{.user.Email}}
来插入用户的名字和邮箱地址。 - 使用
.user.JoinDate.Format "2006-01-02"
来格式化时间戳为可读的日期格式。 - 注释部分展示了如何使用
template.HTML
来输出原始HTML内容,但需要注意这可能带来安全风险,因此只有在确定内容是安全的情况下才应使用。
- 使用
通过这种方式,你可以在 Go 代码和 HTML 模板之间传递数据,并且利用 Go 的模板引擎来进行动态内容生成。
函数调用
可以在模板中调用函数,并且可以将结果直接插入到 HTML 中。
html
<p>The result is: {{add 1 2}}</p>
- 在上面的例子中,
add
是一个自定义函数,它接收两个参数并返回它们的和。
条件语句
可以使用 if
和 else
进行条件判断。
html
{{if .IsAdmin}}
<p>Welcome Admin!</p>
{{else}}
<p>Welcome User!</p>
{{end}}
- 支持
if
、else if
和else
结构。
下面是一个使用 Gin 框架和 Go 的 html/template
进行条件语句处理的简单示例。这个例子展示了如何在模板中根据传递的数据执行不同的逻辑分支。
示例:条件语句
Go 文件(main.go
)
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 定义一个结构体来表示用户信息
type User struct {
Name string
IsAdmin bool
}
func main() {
// 创建默认的 Gin 路由器
r := gin.Default()
// 加载HTML模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个路由处理函数,渲染HTML模板并传递用户数据
r.GET("/user", func(c *gin.Context) {
// 创建两个不同权限级别的用户实例
user1 := User{
Name: "Alice",
IsAdmin: true,
}
user2 := User{
Name: "Bob",
IsAdmin: false,
}
// 根据查询参数 'name' 来决定传递哪个用户实例给模板
name := c.Query("name")
var user User
if name == "Alice" {
user = user1
} else {
user = user2
}
// 渲染 "profile.html" 模板,并传递用户数据给模板
c.HTML(http.StatusOK, "profile.html", gin.H{
"title": "User Profile",
"user": user,
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
HTML 模板文件(templates/profile.html
)
html
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title> <!-- 使用 .title 变量设置页面标题 -->
</head>
<body>
<h1>User Profile</h1>
<!-- 插入用户名 -->
<p>Name: {{.user.Name}}</p>
<!-- 使用 if-else 语句来判断用户是否为管理员 -->
{{if .user.IsAdmin}}
<p>Welcome Admin!</p>
<p>You have administrative privileges.</p>
{{else}}
<p>Welcome User!</p>
<p>You do not have administrative privileges.</p>
{{end}}
<!-- 你还可以添加更多的逻辑分支,例如 elseif -->
<!--
{{if .user.IsAdmin}}
<p>Welcome Admin!</p>
{{else if .user.IsModerator}}
<p>Welcome Moderator!</p>
{{else}}
<p>Welcome User!</p>
{{end}}
-->
</body>
</html>
代码注释解释
-
Go 文件 (
main.go
)User
结构体定义了用户信息的字段,包括名字和是否是管理员。- 在
/user
路由处理函数中,创建了两个不同权限级别的User
实例 (user1
和user2
)。 - 根据 URL 查询参数
name
的值选择要传递给模板的用户实例。 - 使用
c.HTML()
方法将选定的用户实例以及页面标题一起传递给模板。
-
HTML 模板文件 (
templates/profile.html
)- 使用
{``{.title}}
来插入来自 Go 代码中的页面标题。 - 使用
{``{.user.Name}}
来插入用户的名称。 - 使用
{``{if .user.IsAdmin}} ... {``{else}} ... {``{end}}
来进行条件判断:- 如果用户是管理员,则显示欢迎管理员的消息;
- 否则,显示普通用户的欢迎消息。
- 注释部分展示了如何使用
if-else if-else
语句来进行多分支逻辑判断,虽然在这个例子中没有用到IsModerator
字段,但这是为了展示更复杂的条件逻辑。
- 使用
通过这种方式,你可以在 Go 代码和 HTML 模板之间传递数据,并且利用 Go 的模板引擎来进行动态内容生成,同时可以根据条件改变页面内容。
循环
可以使用 range
对数组、切片、map 等进行迭代。
html
<ul>
{{range .Items}}
<li>{{.}}</li>
{{end}}
</ul>
.
在range
内部表示当前迭代项。
下面是一个使用 Gin 框架和 Go 的 html/template
进行循环语句处理的简单示例。这个例子展示了如何在模板中遍历一个列表,并根据列表中的数据动态生成 HTML 内容。
示例:循环语句
Go 文件(main.go
)
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 定义一个结构体来表示项目信息
type Project struct {
Name string
Status string
}
func main() {
// 创建默认的 Gin 路由器
r := gin.Default()
// 加载HTML模板文件
r.LoadHTMLGlob("templates/*")
// 定义一个路由处理函数,渲染HTML模板并传递项目列表数据
r.GET("/projects", func(c *gin.Context) {
// 创建一些项目实例
projects := []Project{
{Name: "Project Alpha", Status: "Active"},
{Name: "Project Beta", Status: "Completed"},
{Name: "Project Gamma", Status: "Pending"},
}
// 渲染 "projects.html" 模板,并传递项目列表给模板
c.HTML(http.StatusOK, "projects.html", gin.H{
"title": "Project List",
"projects": projects,
})
})
// 启动HTTP服务,默认监听0.0.0.0:8080
r.Run()
}
HTML 模板文件(templates/projects.html
)
html
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title> <!-- 使用 .title 变量设置页面标题 -->
</head>
<body>
<h1>Project List</h1>
<!-- 使用 range 语句遍历项目列表 -->
<ul>
{{range .projects}}
<li>
<strong>{{.Name}}</strong> - Status: {{.Status}}
<!-- 根据项目状态添加不同类名或显示不同图标 -->
{{if eq .Status "Active"}}
<span class="badge badge-success">Active</span>
{{else if eq .Status "Completed"}}
<span class="badge badge-primary">Completed</span>
{{else}}
<span class="badge badge-warning">Pending</span>
{{end}}
</li>
{{end}}
</ul>
</body>
</html>
代码注释解释
-
Go 文件 (
main.go
)Project
结构体定义了项目信息的字段,包括名称和状态。- 在
/projects
路由处理函数中,创建了一个包含多个项目的切片projects
。 - 使用
c.HTML()
方法将项目列表以及页面标题一起传递给模板。
-
HTML 模板文件 (
templates/projects.html
)- 使用
{``{.title}}
来插入来自 Go 代码中的页面标题。 - 使用
{``{range .projects}} ... {``{end}}
来遍历从 Go 代码传递过来的projects
切片。- 对于每个项目,使用
{``{.Name}}
和{``{.Status}}
插入项目名称和状态。 - 使用嵌套的条件语句
{``{if eq .Status "Active"}} ... {``{else if eq .Status "Completed"}} ... {``{else}} ... {``{end}}
根据项目的状态来决定显示的内容或样式。
- 对于每个项目,使用
{``{range}}
循环会为每个项目生成一个<li>
元素,从而动态地构建一个无序列表。
- 使用
通过这种方式,你可以在 Go 代码和 HTML 模板之间传递数据,并且利用 Go 的模板引擎来进行动态内容生成,同时可以根据循环中的数据动态改变页面内容。这种方法非常适合用于展示列表、表格或其他需要重复元素的界面。
模板继承与包含
定义模板块
可以定义多个模板块,然后在主模板中引用它们。
html
{{define "header"}}
<header>
<h1>Site Header</h1>
</header>
{{end}}
{{define "content"}}
<main>
<p>Main content goes here.</p>
</main>
{{end}}
{{define "footer"}}
<footer>
<p>Site Footer</p>
</footer>
{{end}}
引用模板块
在主模板中引用之前定义的模板块。
html
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
{{template "header" .}}
{{template "content" .}}
{{template "footer" .}}
</body>
</html>
转义输出
Go 的 html/template
会自动转义输出以防止 XSS(跨站脚本攻击)。
html
<p>User input: {{.UserInput}}</p>
- 如果
.UserInput
包含 HTML 标签或特殊字符,这些内容会被转义,从而安全地显示为纯文本。
原始HTML输出
如果确实需要输出原始 HTML,可以使用 template.HTML
类型。
go
data := gin.H{
"RawHTML": template.HTML("<strong>Bold Text</strong>"),
}
html
<div>{{.RawHTML}}</div>
- 注意,只有当你确定内容是安全的时候才应该这样做,因为这可能会带来安全风险。
注释
模板中也可以包含注释,这些注释不会出现在最终的 HTML 输出中。
html
{{/* This is a comment and will not be rendered */}}
自定义函数
你还可以注册自定义函数,以便在模板中使用。
go
func init() {
gin.Template.FuncMap = template.FuncMap{
"formatAsDate": formatAsDate,
}
}
func formatAsDate(t time.Time) string {
return t.Format("2006-01-02")
}
html
<p>Date: {{formatAsDate .CreatedAt}}</p>
以上就是 Gin 模板的基本语法和一些常用的功能。通过这些功能,你可以创建动态且安全的 HTML 页面。
gin 模板基本语法 循环语句 1个示例 代码需要注释