当前位置: 首页 > 工具软件 > Go template > 使用案例 >

go Template

刘元青
2023-12-01

html/template包实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。它提供了和text/template包相同的接口,Go语言中输出HTML的场景都应使用text/template包。

模板示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello</title>
</head>
<body>
    <p>Hello {{.}}</p>
</body>
</html>

通过将模板应用于一个数据结构(即该数据结构作为模板的参数)来执行,来获得输出。模板中的注释引用数据接口的元素(一般如结构体的字段或者字典的键)来控制执行过程和获取需要呈现的值。模板执行时会遍历结构并将指针表示为’.‘(称之为”dot”)指向运行过程中数据结构的当前位置的值。

用作模板的输入文本必须是utf-8编码的文本。”Action”—数据运算和控制单位—由”“界定;在Action之外的所有文本都不做修改的拷贝到输出中。Action内部不能有换行,但注释可以有换行。

func sayHello(w http.ResponseWriter, r *http.Request) {
    // 解析指定文件生成模板对象
    tmpl, err := template.ParseFiles("./hello.html")
    if err != nil {
        fmt.Println("create template failed, err:", err)
        return
    }
    // 利用给定数据渲染模板,并将结果写入w
    tmpl.Execute(w, "5lmh.com")
}

解析模板

// 创建模板对象,并为其添加一个模板名称
func New(name string) *Template {}
// 解析字符串 
// 可以使用template.New("name").Parse(src string) 
// 来创建模板对象,并完成解析模板内容。
func (t *Template) Parse(src string) (*Template, error) {}
// ParseFiles 方法可以解析模板文件,并得到模板对象
func ParseFiles(filenames ...string) (*Template, error) {}
// ParseGlob方法用于批量解析文件
// 比如在当前目录下有以h开头的模板10个
// 使用template.ParseGlob("h*")即可页将10个模板文件一起解析出来
func ParseGlob(pattern string) (*Template, error) {}

模板渲染

func (t *Template) Execute(wr io.Writer, data interface{}) error {}
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {}

使用New在创建时就为其添加一个模板名称,并且执行t.Execute()会默认去寻找该名称进行数据融合。

使用ParseFiles一次指定多个文件加载多个模板进来,就不可以使用t.Execute()来执行数据融合,可以通过t.ExecuteTemplate()方法指定模板名称来执行数据融合。

模板语法

  1. {{.}}
  2. 模板语法都包含在{{和}}中间,其中{{.}}中的点表示当前对象。
  3. 传入一个结构体对象时,可以根据.来访问结构体的对应字段。
type UserInfo struct {
    Name   string
    Gender string
    Age    int
}

func sayHello(w http.ResponseWriter, r *http.Request) {
    // 解析指定文件生成模板对象
    tmpl, err := template.ParseFiles("./hello.html")
    if err != nil {
        fmt.Println("create template failed, err:", err)
        return
    }
    // 利用给定数据渲染模板,并将结果写入w
    user := UserInfo{
        Name:   "枯藤",
        Gender: "男",
        Age:    18,
    }
    tmpl.Execute(w, user)
}

同理,当传入的变量是map时,也可以在模板文件中通过.根据key来取值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello</title>
</head>
<body>
    <p>Hello {{.Name}}</p>
    <p>性别:{{.Gender}}</p>
    <p>年龄:{{.Name}}</p>
</body>
</html>

注释

    {{/* a comment */}}
    注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止。

pipeline

pipeline是指产生数据的操作。比如{{.}}、{{.Name}}等。Go的模板语法中支持使用管道符号|链接多个命令,用法和unix下的管道类似:|前面的命令会将运算结果(或返回值)传递给后一个命令的最后一个位置。

注意 : 并不是只有使用了|才是pipeline。Go的模板语法中,pipeline的概念是传递数据,只要能产生数据的,都是pipeline。

变量

Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下:

 $variable := pipeline
{{ $obj := "jack" }}
{{ $obj }} // 输出:jack

其中$variable是变量的名字。声明变量的action不会产生任何输出。

条件判断

{{if pipeline}} T1 {{end}}

{{if pipeline}} T1 {{else}} T0 {{end}}

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

range

Go的模板语法中使用range关键字进行遍历,有以下两种写法,其中pipeline的值必须是数组、切片、字典或者通道。

{{range pipeline}} T1 {{end}}
如果pipeline的值其长度为0,不会有任何输出

{{range pipeline}} T1 {{else}} T0 {{end}}
如果pipeline的值其长度为0,则会执行T0。

with

{{with pipeline}} T1 {{end}}
如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。

{{with pipeline}} T1 {{else}} T0 {{end}}
如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。

预定义函数

and
    函数返回它的第一个empty参数或者最后一个参数;
    就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
    返回第一个非empty参数或者最后一个参数;
    亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
    返回它的单个参数的布尔值的否定
len
    返回它的参数的整数类型长度
index
    执行结果为第一个参数以剩下的参数为索引/键指向的值;
    如"index x 1 2 3"返回x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
print
    即fmt.Sprint
printf
    即fmt.Sprintf
println
    即fmt.Sprintln
html
    返回其参数文本表示的HTML逸码等价表示。
urlquery
    返回其参数文本表示的可嵌入URL查询的逸码等价表示。
js
    返回其参数文本表示的JavaScript逸码等价表示。
call
    执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
    如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
    其中Y是函数类型的字段或者字典的值,或者其他类似情况;
    call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
    该函数类型值必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
    如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误

比较函数

布尔函数会将任何类型的零值视为假,其余视为真。

下面是定义为函数的二元比较运算的集合:

eq      如果arg1 == arg2则返回真
ne      如果arg1 != arg2则返回真
lt      如果arg1 < arg2则返回真
le      如果arg1 <= arg2则返回真
gt      如果arg1 > arg2则返回真
ge      如果arg1 >= arg2则返回真

为了简化多参数相等检测,eq(只有eq)可以接受2个或更多个参数,它会将第一个参数和其余参数依次比较,返回下式的结果:

{{eq arg1 arg2 arg3}}

比较函数只适用于基本类型(或重定义的基本类型,如”type Celsius float32”)。但是,整数和浮点数不能互相比较。

嵌套template

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>tmpl test</title>
</head>
<body>

    <h1>测试嵌套template语法</h1>
    <hr>
    {{template "ul.html"}}
    <hr>
    {{template "ol.html"}}
</body>
</html>

{{ define "ol.html"}}
<h1>这是ol.html</h1>
<ol>
    <li>吃饭</li>
    <li>睡觉</li>
    <li>打豆豆</li>
</ol>
{{end}}

示例

func main(){
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		if request.Method=="GET"{
			html,_:=template.ParseFiles("templates/index.tmpl")
			data:=make([]map[interface{}]interface{},0,10)
			for i:=0;i<10;i++{
				data=append(data, map[interface{}]interface{}{
					"id":i+1,
					"message":[]interface{}{
						"唱","跳","rap","篮球",
					},
					"data": map[string]interface{}{
						"name":"123",
						"age":rand.Int(),
					},
				})
			}
			err := html.Execute(writer, data)
			if err != nil {
				return 
			}
		}
	})

	_=http.ListenAndServe("127.0.0.1:8080",nil)
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    {{ range $index,$value :=. }}
        <p>
            <p>id:
                <span>{{ $value.id }}</span>
            </p>
            <p>message:
                {{ range $i,$item:= $value.message}}
                <span>{{ $item }} </span>
                {{ end }}
            </p>
            <p>data:
                <span>{{ $value.data.name }}</span>
                <br>
                <span>{{ $value.data.age }}</span>
            </p>
        </p>
    {{ end }}
</body>
</html>
 类似资料:

相关阅读

相关文章

相关问答