Go 语言内置了一个强大的模板引擎 html/template,可以帮助我们轻松地构建动态 HTML 页面。
html/template
Go 标准库 (html/template) 实现数据驱动模板,用于生成安全的 HTML 输出,防止代码注入。它提供与text/template相同的界面,并且只要输出是 HTML, 就应该使用它来代替 text/template 。
一些基础
- 变量: 使用
{{.VariableName}}语法访问变量。点号.用于访问结构体字段或映射中的值。 - 条件语句: 使用
{{if expr}} ... {{end}}语法来实现条件判断。 - 循环: 使用
{{range expr}} ... {{end}}语法来遍历数组、切片或映射。在循环内部,可以使用.访问当前元素。 - 模板函数: Go HTML 模板提供了一些内置函数,如
len、index等。您也可以定义自己的自定义函数。 - 管道: 您可以使用管道
|将函数的输出作为下一个函数的输入,类似于 Unix 命令行。 - 注释: 使用
{{/* 注释内容 */}}语法添加注释
更多参考: pkg.go.dev/text/templa…
使用参考:
<!-- 变量 -->
<h1>{{.Title}}</h1>
<p>{{.Content}}</p>
<!-- 条件语句 -->
{{if .IsAdmin}}
<p>Welcome, admin!</p>
{{else}}
<p>Welcome, user!</p>
{{end}}
<!-- 循环 -->
<ul>
{{range .Items}}
<li>{{.}}</li>
{{end}}
</ul>
<!-- 函数 -->
<p>There are {{len .Items}} items.</p>
<!-- 管道 -->
<p>Capitalized title: {{.Title | title}}</p>
<!-- 注释 -->
{{/* This is a comment and will not be rendered */}}
快速开始
让我们从一个简单的例子快速开始。
首先,我们创建一个模板 index.html,其中包含以下内容:
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
</head>
<body>
<h1>{{.Theme}}</h1>
<p>{{.Content}}</p>
</body>
</html>
其次,我们可以使用以下方式渲染这个模板:
package main
import (
"html/template"
"os"
)
func main() {
t, err := template.ParseFiles("index.html")
if err != nil {
panic(err)
}
data := struct {
Title string
Theme string
Content string
}{
Title: "Welcome to jefffff's blog",
Theme: "Website Template",
Content: "Balalalalalala ",
}
file, err := os.Create("output.html")
if err != nil {
panic(err)
}
defer func() {
err = file.Close()
if err != nil {
return
}
}()
err = t.Execute(file, data)
if err != nil {
panic(err)
}
}
执行输出一个onput.html,内容如下
<!DOCTYPE html>
<html>
<head>
<title>Welcome to jefffff's blog</title>
</head>
<body>
<h1>Website Template</h1>
<p>Balalalalalala </p>
</body>
</html>
效果如下
上例中,首先通过 template.ParseFiles() 函数解析 index.html 并创建一个模板对象。其次,将定义好的动态数据的结构,并使用 t.Execute() 函数将数据渲染到output.html的文件里。
博客页面
接着,我们渲染一个复杂点的博客页面。
首先,我们创建一个模板页 post.html:
<!DOCTYPE html>
<html>
<head>
<title>Blog Post</title>
</head>
<body>
<h1>{{ .Post.Title }}</h1>
<p>Author: {{ .Post.Author }}</p>
<p>{{ .Post.Content }}</p>
<h2>Comments</h2>
{{ if gt (len .Post.Comments) 0 }}
<ul>
{{ range .Post.Comments }}
<li>
<strong>{{ .Author }}:</strong>
<p>{{ .Content }}</p>
<p>Upvotes: {{ .Upvotes }}</p>
</li>
{{ end }}
</ul>
{{ else }}
<p>There are no comments yet.</p>
{{ end }}
<h2>Reference</h2>
{{ if gt (len .Reference) 0 }}
<ul>
{{ range .Reference }}
<li><a href="/posts/{{ .Title }}">{{ .Author }}</a></li>
{{ end }}
</ul>
{{ else }}
<p>There are no reference.</p>
{{ end }}
</body>
</html>
接着,golang渲染Blog模板:
package main
import (
"html/template"
"log"
"net/http"
"os"
)
// Post 博客
type Post struct {
Title string
Author string
Content string
Comments []Comment
Reference []Post
}
// Comment 评论
type Comment struct {
Author string
Content string
Upvotes int
}
func main() {
tmpl := template.Must(template.ParseFiles("post.html"))
post := Post{
Title: "Introduction to Go Html Template",
Author: "Jeff",
Content: "This is a blog about the use of go html template.",
Comments: []Comment{
{Author: "Li Lei", Content: "favorites!", Upvotes: 10},
{Author: "Han MeiMei", Content: "I have collected, thanks!", Upvotes: 5},
},
Reference: []Post{
{Title: "Go Doc", Author: "Jack Lee"},
{Title: "Blog How use html/template", Author: "Tom "},
},
}
data := struct {
Post Post
Reference []Post
}{
Post: post,
Reference: post.Reference,
}
file, err := os.Create("post_output.html")
if err != nil {
panic(err)
}
defer func() {
err = file.Close()
if err != nil {
return
}
}()
err = tmpl.Execute(file, data)
if err != nil {
panic(err)
}
}
生成的post_output.html详细如下:
<!DOCTYPE html>
<html>
<head>
<title>Blog Post</title>
</head>
<body>
<h1>Introduction to Go Html Template</h1>
<p>Author: Jeff</p>
<p>This is a blog about the use of go html template.</p>
<h2>Comments</h2>
<ul>
<li>
<strong>Li Lei:</strong>
<p>favorites!</p>
<p>Upvotes: 10</p>
</li>
<li>
<strong>Han MeiMei:</strong>
<p>I have collected, thanks!</p>
<p>Upvotes: 5</p>
</li>
</ul>
<h2>Reference</h2>
<ul>
<li><a href="/posts/Go%20Doc">Jack Lee</a></li>
<li><a href="/posts/Blog%20How%20use%20html/template">Tom </a></li>
</ul>
</body>
</html>
web效果如下:
上例中:
- 定义了博客对象 Post,其包括标题、内容、评论、参考文献等。
- 通过template.Must(template.ParseFiles("post.html")) 来解析的HTML 模板
post.html。 - 创建了一篇示例博文post。
- 创建一个文件post_output.html, 使用tmpl.Execute(file, data)将数据写入文件。
当然,我们也可以将渲染好的html发布到web server。
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := tmpl.Execute(w, data)
if err != nil {
log.Println("Error rendering template:", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
})
log.Println("Starting server on :8080")
http.ListenAndServe(":8080", nil)
访问http://localhost:8080/, 显示post_out.html
上例中,创建一个 HTTP 处理函数,使用 tmpl.Execute(w, data) 将博客数据渲染的html写入http.Writer。
比较运算符
布尔函数将任何零值视为假,将非零值视为真。 还有一组定义为函数的二进制比较运算符:
eq
Returns the boolean truth of arg1 == arg2
ne
Returns the boolean truth of arg1 != arg2
lt
Returns the boolean truth of arg1 < arg2
le
Returns the boolean truth of arg1 <= arg2
gt
Returns the boolean truth of arg1 > arg2
参考例子
{{ if eq .Value 0 }}
<p>Value is zero</p>
{{ end }}
{{ if ne .Name "John" }}
<p>Name is not John</p>
{{ end }}
{{ if lt .Age 18 }}
<p>User is underage</p>
{{ end }}
{{ if le .Score 100 }}
<p>Score is less than or equal to 100</p>
{{ end }}
{{ if gt .Temperature 30 }}
<p>Temperature is above 30 degrees</p>
{{ end }}
{{ if ge .Salary 50000 }}
<p>Salary is greater than or equal to 50,000</p>
{{ end }}
小结
本文简要介绍了Go语言的html/template,以及通过一个构建动态博客HTML页面的例子,来演示使用该库基础使用。如果我们在需要经常模板渲染的场景,建议可以考虑缓存已编译的模板以提高性能。
参考
- go doc pkg.go.dev/html/templa…
- template functions pkg.go.dev/text/templa…
- Go - Template 最全的模板说明juejin.cn/post/735983…