03 Go模板
1 template模板初识
hello.tmpl
<!DOCTYPE html>
<html lang="zh-CN">
<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>
<hr>
{{/*1 template模板初识*/}}
<p> hello {{ . }} </p>
<hr/>
{{/*2 模板语法详解*/}}
{{/*当我们传入的变量是map或结构体时,可以在模板文件中通过.根据key来取值*/}}
<p> 姓名: {{ .user1.Name }}</p>
<p> 性别: {{ .user1.Gender }}</p>
<p> 年龄: {{ .user1.Age }}</p>
<hr/>
{{/*变量*/}}
{{ $obj := .user1.Name }}
<p>变量: {{ $obj }}</p>
<hr/>
{{/*移除空格*/}}
<p>去除模板内容左侧的所有空白符号 {{- .user1.Age -}} 去除模板内容右侧的所有空白符号</p>
<hr/>
{{/*条件判断*/}}
<p>条件判断:
{{ $Age := .user1.Age }}
{{ $Gender := .user1.Gender }}
{{ if $Gender }}
{{ $Gender }}
{{ else if $Age }}
{{ $Age }}
{{ else }}
啥也没有
{{ end }}
</p>
<hr/>
{{/*比较函数*/}}
{{/*eq 如果arg1 == arg2则返回真 可以比较字符串*/}}
{{/*ne 如果arg1 != arg2则返回真 可以比较字符串*/}}
{{/*lt 如果arg1 < arg2则返回真*/}}
{{/*le 如果arg1 <= arg2则返回真*/}}
{{/*gt 如果arg1 > arg2则返回真*/}}
{{/*ge 如果arg1 >= arg2则返回真*/}}
<p>比较函数:
{{ if lt .user1.Age 18 }}
好好学习
{{ else if gt .user1.Age 18 }}
好好工作
{{ else }}
好好养老
{{ end }}
</p>
<hr/>
{{/*with 造一个局部作用域*/}}
{{/*{{with pipeline}} T1 {{end}}*/}}
{{/*如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。*/}}
{{/*{{with pipeline}} T1 {{else}} T0 {{end}}*/}}
{{/*如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。*/}}
<p>with:局部作用域:</p>
{{ with .user2 }}
<li>{{ .name }}</li>
<li>{{ .gender }}</li>
<li> {{ .age }}</li>
{{ else }}
没有数据
{{ end }}
<hr/>
{{/*range 其中pipeline的值必须是数组、切片、map或者通道*/}}
{{/*{{range pipeline}} T1 {{end}}*/}}
{{/*如果pipeline的值其长度为0,不会有任何输出*/}}
{{/*{{range pipeline}} T1 {{else}} T0 {{end}}*/}}
{{/*如果pipeline的值其长度为0,则会执行T0。*/}}
<p>range 遍历</p>
{{ $slice := .user2 }}
{{ range $slice }}
<li> {{ . }} </li>
{{ end }}
<hr/>
<p>range遍历带索引</p>
{{ range $idx,$val := $slice }}
<p>{{ $idx }} - {{ $val }}</p>
{{ else }}}
没有数据
{{ end }}
<hr/>
{{/*预定义函数*/}}
{{/*执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。*/}}
{{/*自定义函数*/}}
</body>
</html>
main.go
package main
import (
"fmt"
"html/template"
"net/http"
)
//1 template模板初识
//1.1 定义一个hello.tmpl的模板文件
//1.2 解析模板和渲染模板
func sayHello01(w http.ResponseWriter, r *http.Request) {
// 解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./hello.tmpl")
if err != nil {
fmt.Println("create template failed,err:", err)
return
}
// 利用给定数据渲染模板,并将数据写入w
err = tmpl.Execute(w, "go语言")
if err != nil {
fmt.Println(err)
return
}
}
//2 模板语法详解
//2.1{{.}}中的点表示当前对象,当我们传入一个结构体对象时,我们可以根据.来访问结构体的对应字段
func sayHello02(w http.ResponseWriter, r *http.Request) {
type UserInfo struct {
Name string
Gender string
Age int
}
tmpl, err := template.ParseFiles("./hello.tmpl")
if err != nil {
fmt.Println(err)
return
}
// 结构体字段名必须是大写才能被模板访问到
user1 := UserInfo{
Name: "张三",
//Gender: "男",
Age: 27,
}
// map的key大写或小写都能被模板访问到
user2 := map[string]interface{}{
"name": "小红",
"gender": "女",
"age": 18,
}
err = tmpl.Execute(w, map[string]interface{}{
"user1": &user1,
"user2": &user2,
})
if err != nil {
fmt.Println(err)
return
}
}
func main() {
//1 template模板初识
http.HandleFunc("/01", sayHello01)
//2 模板语法详解
http.HandleFunc("/02", sayHello02)
// 启动服务端
fmt.Println("server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}
2 模板嵌套
main.go
package main
import (
"fmt"
"html/template"
"net/http"
)
// 我们可以在template中嵌套其他的template。这个template可以是单独的文件,也可以是通过define定义的template。
func nestTing(w http.ResponseWriter, r *http.Request) {
// 定义模板
// 解析模板
// 在解析模板时,被嵌套的模板一定要在后面解析,t.tmpl模板中嵌套了ul.tmpl,所以ul.tmpl要在t.tmpl后进行解析
tmpl, err := template.ParseFiles("./t.tmpl", "./ul.tmpl")
if err != nil {
fmt.Println(err)
return
}
// 渲染模板
type userInfo struct {
Name string
Gender string
Age int
}
user := userInfo{
Name: "张三",
Gender: "男",
Age: 30,
}
err = tmpl.ExecuteTemplate(w, "t.tmpl", user)
if err != nil {
fmt.Println(err)
return
}
}
func main() {
http.HandleFunc("/", nestTing)
fmt.Println("http server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}
t.tmpl
<!DOCTYPE html>
<html lang="zh-CN" xmlns="http://www.w3.org/1999/html">
<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/>
{{/*单独的文件*/}}
<h3 style="color: blueviolet">ul.tmpl</h3>
{{ template "ul.tmpl" . }}
<hr/>
{{/* 通过define定义的template */}}
<h3 style="color: blueviolet">define ol.tmpl</h3>
{{ template "ol.tmpl" }}
<hr/>
<h3 style="color: blueviolet">传参</h3>
<p> t.tmpl->姓名:{{ .Name }} </p>
<p> t.tmpl->性别:{{ .Gender }} </p>
<p> t.tmpl->年龄:{{ .Age }} </p>
<hr/>
</body>
</html>
{{/* 通过define定义的template */}}
{{ define "ol.tmpl" }}
<ol>
<li>ol.tmpl->吃饭{{ .Name }}</li>
<li>ol.tmpl->睡觉</li>
<li>ol.tmpl->打豆豆</li>
</ol>
{{ end }}
ul.tmpl
<li>ul.tmpl->注释{{ .Name }}</li>
<li>ul.tmpl->日志{{ .Gender }}</li>
<li>ul.tmpl->测试{{ .Age }}</li>
3 模板继承
base.tmpl
{{/*定义根模板*/}}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Go Templates</title>
<style>
* {
margin: 0;
}
.nav {
top: 0;
height: 70px;
width: 100%;
position: fixed;
background-color: bisque;
}
.main {
margin-top: 70px;
}
.menu {
left: 0;
height: 100%;
width: 20%;
position: fixed;
background-color: lightcoral;
}
.content {
text-align: center;
}
</style>
</head>
<body>
<div class="nav"></div>
<div class="main">
<div class="menu"></div>
<div class="content">
{{/*定义块模板,用于被替换, "."表示将base根模板接收的数据传入当前定义的块 */}}
{{ block "content" . }} {{ end }}
</div>
</div>
</body>
</html>
home.tmpl
{{/*继承根模板,"."表示base根模板接收数据*/}}
{{ template "base.tmpl" . }}
{{/*重新定义块模板*/}}
{{ define "content" }}
<p> 这是home页面 </p>
{{/* "."表示传入的渲染数据 */}}
<p> hello {{ . }}</p>
{{ end }}
index.tmpl
{{/*继承根模板,"."表示base根模板接收数据*/}}
{{ template "base.tmpl" . }}
{{/*重新定义块模板*/}}
{{ define "content" }}
<p> 这是index页面 </p>
{{/* "."表示传入的渲染数据 */}}
<p> hello {{ . }}</p>
{{ end }}
main.go
package main
import (
"fmt"
"html/template"
"net/http"
)
// 模板继承 block
func index(w http.ResponseWriter, r *http.Request) {
//定义模板
//解析模板, 根模板base.tmpl优先于index.tmpl被加载
tmpl, err := template.ParseFiles("./templates/base.tmpl", "./templates/index.tmpl")
if err != nil {
fmt.Println(err)
return
}
//渲染模板,通过ExecuteTemplate渲染指定的模板
msg := "this is index pag"
err = tmpl.ExecuteTemplate(w, "index.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}
func home(w http.ResponseWriter, r *http.Request) {
//定义模板
//解析模板, 根模板base.tmpl优先于home.tmpl被加载
tmpl, err := template.ParseFiles("./templates/base.tmpl", "./templates/home.tmpl")
if err != nil {
fmt.Println(err)
return
}
//渲染模板,通过ExecuteTemplate渲染指定的模板
msg := "this is home page"
err = tmpl.ExecuteTemplate(w, "home.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}
func main() {
// 路由匹配
http.HandleFunc("/index", index)
http.HandleFunc("/home", home)
// 启动服务端
fmt.Println("http Server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}
4 模板补充
htmlTemplate.tmpl
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
{{ . }}
</body>
</html>
identifier.tmpl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{[/*修改默认的标识符*/]}
{[ . ]}
</body>
</html>
main.go
package main
import (
"fmt"
"html/template"
"net/http"
)
// 1.修改默认的标识符
func identifier(w http.ResponseWriter, r *http.Request) {
//Go标准库的模板引擎使用花括号 {{}} 作为标识,而许多前端框架(如Vue和AngularJS)也使用 {{}} 作为标识符,
//所以当我们同时使用Go语言模板引擎和以上前端框架时就会出现冲突,这个时候我们需要修改标识符,修改前端的或者
//修改Go语言的。这里演示如何修改Go语言模板引擎默认的标识符。
tmpl, err := template.New("identifier").Delims("{[", "]}").ParseFiles("./templates/identifier.tmpl")
if err != nil {
fmt.Println(err)
return
}
msg := "this is a identifier page"
err = tmpl.ExecuteTemplate(w, "identifier.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}
// 2.html/template
func htmlTemplate(w http.ResponseWriter, r *http.Request) {
// html/template(默认)针对的是需要返回HTML内容的场景,在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击。
tmpl, err := template.ParseFiles("./templates/htmlTemplate.tmpl")
if err != nil {
fmt.Println(err)
return
}
// 传入JavaScript代码,渲染后会在页面上显示出转义后的JS内容
msg := "<script>alert('hello go 语言')</script>"
err = tmpl.ExecuteTemplate(w, "htmlTemplate.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}
func main() {
//路由匹配
//1.修改默认的标识符
http.HandleFunc("/identifier", identifier)
//2.html/template
http.HandleFunc("/htmlTemplate", htmlTemplate)
//启动服务
fmt.Println("http server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}