您现在的位置是:网站首页> Go语言
GO语言html模板
- Go语言
- 2021-03-09
- 790人已阅读
模板
一个模板是一个字符串或一个文件,里面包含了一个或多个由双花括号包含的{{action}}对象。大部分的字符串只是按面值打印,但是对于actions部分将触发其它的行为。每个actions都包含了一个用模板语言书写的表达式,一个action虽然简短但是可以输出复杂的打印值,模板语言包含通过选择结构体的成员、调用函数或方法、表达式控制流if-else 语句range循环语句,还有其它实例化模板等诸多特性。Action内部不能有换行,但注释可以有换行。
示例
模板执行时会遍历结构并将指针表示为’.‘(称之为”dot”)指向运行过程中数据结构的当前位置的值。
用作模板的输入文本必须是utf-8编码的文本。
Html示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello</title> </head> <body> <p>Hello {{.}}!</p> </body> </html>
GO server端:
func sayHi(w http.ResponseWriter,r *http.Request) { // 解析指定文件生成模板对象 tem,err := template.ParseFiles("xx/hello.html") if err != nil{ fmt.Println("读取文件失败,err",err) return } // 利用给定数据渲染模板,并 tem.Execute(w,"Ares") } func main() { http.HandleFunc("/",sayHi) err := http.ListenAndServe("127.0.0.1:8888",nil) if err != nil{ fmt.Println("监听失败,err",err) return } }
效果:
?
模板语法
模板语法都包含在{{和}}中间,其中{{.}}中的点表示当前对象。
当我们传入一个结构体对象时,我们可以根据.来访问结构体的对应字段。Html示例:
<html lang="en"> <head> <meta charset="UTF-8"> <title>Hello</title> </head> <body><p>Hello {{.Name}}!</p> <p>年龄 {{.Ae}}!</p> <p>性别 {{.Male}}!</p> </body> </html>
GO server端:
type People struct { Name string Age int Male string } func sayHi(w http.ResponseWriter,r *http.Request) { // 解析指定文件生成模板对象 tem,err := template.ParseFiles("xx/hello.html") if err != nil{ fmt.Println("读取文件失败,err",err) return } // 利用给定数据渲染模板,并将结果写入w People := People{ Name:"Ares", Age:28, Male:"男", } tem.Execute(w,People) } func main() { http.HandleFunc("/",sayHi) err := http.ListenAndServe("127.0.0.1:8888",nil) if err != nil{ fmt.Println("监听失败,err",err) return } }
效果:
?
注释
{{/* a comment */}}
可以多行。注释不能嵌套。
变量
Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下:
$variable := pipeline
示例:
<body> <p>Hello {{.Name}}!</p><p>年龄 {{.Age}}!</p> <p>性别 {{.Male}}!</p> {{ $age := . }} {{ $age.Age }} </body>
条件判断
初始语法:
{{if pipeline}} T1 {{end}} {{if pipeline}} T1 {{else}} T0 {{end}} {{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
示例:
<body> <p>Hello {{.Name}}!</p> <p>年龄 {{.Age}}!</p> <p>性别 {{.Male}}!</p> {{ $age := . }} {{ $age.Age }} {{if gt .Age 18}} <div>成年啦!</div> {{else}} <div>快乐成长!</div> {{end}} </body>
比较函数
布尔函数会将任何类型的零值视为假,其余视为真。
eq 如果arg1 == arg2则返回真 ne 如果arg1 != arg2则返回真 lt 如果arg1 < arg2则返回真 le 如果arg1 <= arg2则返回真 gt 如果arg1 > arg2则返回真 ge 如果arg1 >= arg2则返回真
range
使用range关键字进行遍历,有以下两种写法,其中pipeline的值必须是数组、切片、字典或者通道。
基本语法:
{{range pipeline}} T1 {{end}} 如果pipeline的值其长度为0,不会有任何输出 {{range pipeline}} T1 {{else}} T0 {{end}} 如果pipeline的值其长度为0,则会执行T0。
map示例:
PeopleMap := map[int]People{ 1: {"Ares", 18, "男"}, 2: {"龙猫", 28, "女"}, } tem.Execute(w, PeopleMap)
切片示例:
PeopleSlice := []People{ {"Ares", 18, "男"}, {"龙猫", 28, "女"}, } tem.Execute(w, PeopleSlice)
HTML模板:
<body> <table border="1"> <thead> <tr> <th>序号</th> <th>姓名</th> <th>年龄</th> <th>性别</th> </tr> </thead> <tbody> {{range $index, $user := .}} <tr> <td>{{$index}}</td> <td>{{$user.Name}}</td> <td>{{$user.Age}}</td> <td>{{$user.Male}}</td> </tr> {{end}} </tbody> </table> </body>
效果:
?
预定义函数
执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。
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,模板执行会中断并返回给调用模板执行者该错误;
参考:GO语言标准库
示例:
<p>{{index . 1}}</p> <p>切片长度: {{len .}}</p> <p> {{with index . 1}} {{printf "姓名:%s 年龄:%d 性别:%s" .Name .Age .Male}} {{end}} </p>
效果:
?
自定义函数
自定义一个book函数:
type Book struct { Name string Author string Price float32 } func info(w http.ResponseWriter,r *http.Request) { // 打开一个模板文件 htmlByte,err := ioutil.ReadFile("./info.html") if err != nil{ fmt.Println("读取html文件失败,err",err) return } // 1. 自定义一个函数 // 自定义一个书籍的模板函数 bookFunc := func(arg string) (string, error) { return arg + "真好看!", nil } // 2. 把自定义的函数告诉模板系统 // template.New("info") // 创建一个Template对象 // template.New("info").Funcs(template.FuncMap{"book": bookFunc}) // 给模板系统追加自定义函数 // 解析模板 t,err := template.New("info").Funcs(template.FuncMap{"book": bookFunc}).Parse(string(htmlByte)) if err != nil{ fmt.Println("parse html文件失败,err",err) return } BookMap := map[int]Book{ 1:{"跟Ares一起学GO","Ares",9.9}, 2:{"斗破苍穹","Ares1",99.9}, } t.Execute(w,BookMap) } func main() { http.HandleFunc("/info",info) http.ListenAndServe("127.0.0.1:8888",nil) }
html:
<body> <p> {{with index . 1}} <p>{{book .Name}}</p> {{end}} </p> <p>{{with index . 2}} <p>{{book .Name}}</p> {{end}} </p> </body>
效果:
?
模板嵌套
我们可以在template中嵌套其他的template。这个template可以是单独的文件,也可以是通过define定义的template.
func index(w http.ResponseWriter,r * http.Request) { t , err := template.ParseFiles("./index.html","./test.html") if err != nil{ fmt.Println("读取html文件失败,err",err) return } t.Execute(w,nil) } func main() { http.HandleFunc("/",index) http.ListenAndServe("127.0.0.1:8888",nil) }
index.html:
<body> <h1>测试嵌套template语法</h1> <hr> {{template "test.html"}} <hr> {{/* 在index.html这个模板中调用了另外一个模板:index.html */}} {{template "inside.html"}} </body> </html> {{/* 在index.html这个模板中定义了另外一个模板:inside.html */}} {{ define "inside.html"}} <h1>inside.html</h1> <ol> <li>吃饭</li> <li>睡觉</li> <li>打豆豆</li> </ol> {{end}}
test.html:
<body> <ol> <li>嵌套模板</li> <li>out模板</li> </ol> </body>
效果:
?