Go Libs :html/template (构建动态 HTML 页面)

374 阅读4分钟

Go 语言内置了一个强大的模板引擎 html/template,可以帮助我们轻松地构建动态 HTML 页面。

html/template

Go 标准库 (html/template) 实现数据驱动模板,用于生成安全的 HTML 输出,防止代码注入。它提供与text/template相同的界面,并且只要输出是 HTML, 就应该使用它来代替 text/template 。

一些基础

  1. 变量: 使用 {{.VariableName}} 语法访问变量。点号 . 用于访问结构体字段或映射中的值。
  2. 条件语句: 使用 {{if expr}} ... {{end}} 语法来实现条件判断。
  3. 循环: 使用 {{range expr}} ... {{end}} 语法来遍历数组、切片或映射。在循环内部,可以使用 . 访问当前元素。
  4. 模板函数: Go HTML 模板提供了一些内置函数,如 lenindex 等。您也可以定义自己的自定义函数。
  5. 管道: 您可以使用管道 | 将函数的输出作为下一个函数的输入,类似于 Unix 命令行。
  6. 注释: 使用 {{/* 注释内容 */}} 语法添加注释

更多参考: 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&#39;s blog</title>
</head>
<body>
<h1>Website Template</h1>
<p>Balalalalalala </p>
</body>
</html>

效果如下

image.png

上例中,首先通过 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效果如下:

1716049944056.png

上例中:

  1. 定义了博客对象 Post,其包括标题、内容、评论、参考文献等。
  2. 通过template.Must(template.ParseFiles("post.html")) 来解析的HTML 模板post.html
  3. 创建了一篇示例博文post。
  4. 创建一个文件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页面的例子,来演示使用该库基础使用。如果我们在需要经常模板渲染的场景,建议可以考虑缓存已编译的模板以提高性能。

参考