模板是构建丰富结构的web页面的主要手段。所以需要再深入了解一下。
首先构建一个handler
func templateHandler(writer http.ResponseWriter, request *http.Request) { t, err := template.ParseFiles("./JoelTempWeb/layout.html") if err != nil{ fmt.Fprintln(writer,err) } fmt.Println("template name is ",t.Name()) t.Execute(writer,"hello moon") }
当然需要配套的html模板
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>layout</title></head><body><h3>This is layout</h3>template data:{{ . }}</body></html>
这里的 {{.}}就是显示func templateHandler中的给出的数据 "hello moon" 的。所以,当main里这样之后
http.HandleFunc("/layout/", templateHandler) http.ListenAndServe(":8090", nil)
运行结果如下
hello moon的示例
完整main代码
package mainimport ( "fmt" "joeltest/JoelTempWeb")func main() { JoelTempWeb.JoelHttpPath() JoelTempWeb.JoelListenAndServe() }
完整JoelTempWeb代码
package JoelTempWebimport ( "net/http" "time" "html/template" "fmt" "math/rand" "strconv" "math")//Joel路径func JoelHttpPath() { http.HandleFunc("/layout/", templateHandler) }//Joel监听func JoelListenAndServe() { http.ListenAndServe(":8090", nil) }//=================================func templateHandler(writer http.ResponseWriter, request *http.Request) { t, err := template.ParseFiles("./JoelTempWeb/layout.html") if err != nil{ fmt.Fprintln(writer,err) } fmt.Println("template name is ",t.Name()) t.Execute(writer,"hello moon") }//--------------------------------
模板页layout
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>layout</title></head><body><h3>This is layout</h3>template data:{{ . }}</body></html>
模板还是可以命名的,命名的方式是
t.ExecuteTemplate(writer, "layout", "Hello Moon!!!")
这样,这个模板的名字就是 layout 了。
那么在模板页面中,可以添加 define 来指定 action 的名字。
于是,在模板文件中,可以添加
{{define "layout"}} {{end}}
内容是一样显示的
layout.html的代码变成了这样
{{define "layout"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>layout</title></head><body><h3>This is layout</h3>template data:{{ . }}</body></html>{{end}}
在页面的结构中,可以引入多个模板。比如,我们在引入一个index.html
{{define "index"}} <div style="background-color: chocolate;width: 555px"> this is index.html {{.}} </div> {{end}}
那么在 func templateHandler 中就要修改成这个样子
func templateHandler(writer http.ResponseWriter, request *http.Request) { t, err := template.ParseFiles("./JoelTempWeb/layout.html","./JoelTempWeb/index.html") if err != nil{ fmt.Fprintln(writer,err) } fmt.Println("template name is ",t.Name()) t.ExecuteTemplate(writer, "layout", "Hello Moon!!!") }
因为 index.html 中 define "index" 了,所以,在 layout.html 中加入 index模板的时候就可以直接写 template "index"
{{define "layout"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>layout</title></head><body><h3>This is layout</h3>template data:{{ . }} {{template "index"}}</body></html>{{end}}
这个巧克力色的行,就是index模板添加进来的效果了
当然,如果你把 t.ExecuteTemplate(writer, "layout", "Hello Moon!!!")中的 layout 改为 index ,你就会发现,只剩下index模板的内容了。并且因为使用了index的名字,所以index模板中的 {{.}}也开始起作用了,获得了data
只剩下一行了
直接写字符串模板
模板是可以自己new一个的。不必要存在一个真实的html文件。可以只给出一个名字,这个名字是html文件后缀式的。比如:tmpl.html
请看代码
func Joeltemplate3(writer http.ResponseWriter, request *http.Request) { tmpl := `<!DOCTYPE html><html> <head> <meta http-qquiv="Content-Type" content="text/html; charset=utf-8"> <title>Go Web Programming</title> </head> <body> {{.}} </body></html>` t := template.New("tmpl.html") t, _ = t.Parse(tmpl) t.Execute(writer, "Hello Moon !!!") }
在main里http.HandleFunc这个函数就可以了。
http.HandleFunc("/mm/", JoelTempFunc.Joeltemplate3) server := http.Server{Addr:":8090"} server.ListenAndServe()
执行结果
直接写字符串模板的执行结果
执行模板
如果有多个模板,你只想在执行的时候,才确定执行某一个模板,就需要能够自由的制定要执行的模板。那么要使用到模板名。
当 template.ParseFiles 的参数有多个模板的时候,Execute 方法只会执行第一个模板
t, _ := template.ParseFiles("./JoelTemplate/sayHello.html","./JoelTemplate/sayHelloSon.html") t.Execute(writer, "最爱的是明月")
如果要指定执行第二个模板,这个时候要使用模板名。第二个模板的模板名不包含模板的路径。而且,要想使用模板名指定执行模板的方式,就不能使用 Execute 了,而应该使用 ExecuteTemplate
func Joeltemplate4(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTemplate/sayHello.html","./JoelTemplate/sayHelloMoon.html") t.ExecuteTemplate(writer,"sayHelloMoon.html", "最爱的是明月") }
sayHelloMoon.html模板代码
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>sayHello Title</title></head><body>每天要问候:{{.}}<hr></body></html>
执行模板
条件动作
根据条件选择要执行的动作,格式是
{{if arg}} some content {{end}}
当然,if else end 的模式也是存在的。
{{if arg}} some content {{else}} other content {{end}}
根据这个逻辑,写一个随机数,以数字5为界,大于5或相反,显示不同的内容。
代码示例
//条件动作func processIfHandler(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTempWeb/tmpl.html") rand.Seed(time.Now().Unix()) t.ExecuteTemplate(writer, "tmpl", rand.Intn(10)>5) }
在main里添加这个
http.HandleFunc("/processif/", processIfHandler)
模板这样写
{{define "tmpl"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body><h3>This is random than 5</h3>{{if .}} 就是Moon 大于 5 {{else}} 不是Moon 小于等于 5 {{end}}</body></html>{{end}}
这里的模板调用有个技巧。因为模板文件 define 了名字为 tmpl,所以在加载模板的时候,要这样写
t.ExecuteTemplate(writer, "tmpl", rand.Intn(10)>5)
大于5
小于等于5
迭代动作
可以对数组、切片、映射或者通道进行迭代,在迭代循环内把{{.}}显示为当前迭代的元素。使用 range 关键字实现。像这样
{{range array}} 这里是循环元素显示{{.}} {{end}}
来个对星期的模板加载的迭代动作
//迭代动作func processIterationHandler(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTempWeb/tmplrange.html") dayofweek := []string{"星期日","星期一","星期二","星期三","星期四","星期五","星期六",} t.ExecuteTemplate(writer, "range", dayofweek) }
在main里要添加这个
http.HandleFunc("/processIteration/", processIterationHandler)
模板文件
{{define "range"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body><h3>This is range</h3><ul>{{range .}} <li>{{.}}</li>{{end}}</ul><table style="border-collapse:collapse;">{{range .}} <tr > <td style="border:1px solid orange;">{{.}}</td> </tr>{{end}}</table></body></html>{{end}}
为了好看一点,加了点table样式。
即使你的服务器是windows,路径也是区分大小写的
也可以在模板中添加一个变化,判断有没有数据,没有数据的话显示一个特定的信息。这需要使用 else ,方式类似if else end,是 range else end。
{{define "range"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body><h3>This is range</h3><ul>{{range .}} <li>{{.}}</li>{{end}}</ul><table style="border-collapse:collapse;">{{range .}} <tr > <td style="border:1px solid orange;">{{.}}</td> </tr> {{else}} <tr > <td style="border:1px solid orange;">暂时没有数据...</td> </tr>{{end}}</table></body></html>{{end}}
然后把函数修改一下,去掉数组里的数据。
//迭代动作 func processIterationHandler(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTempWeb/tmplrange.html") //dayofweek := []string{"星期日","星期一","星期二","星期三","星期四","星期五","星期六",} dayofweek := []string{} t.ExecuteTemplate(writer, "range", dayofweek) }
执行结果是这样的
暂时没有数据
设置动作
可以在模板中重新设置参数的值。使用 with 关键字,代码结构像这样
{{with arg}} set to arg {{end}}
也可以添加 else,结构像这样
{{with arg}} set to arg {{else}} still old arg {{end}}
现在看一下模板代码示例
{{define "with"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body><h3>This is with</h3><table style="border-collapse:collapse;">{{with "Moon"}} <tr > <td style="border:1px solid orange;">爱{{.}}</td> </tr>{{else}} <tr > <td style="border:1px solid orange;">原来的数据{{.}}</td> </tr>{{end}}</table></body></html>{{end}}
执行结果
with "Moon"
如果with后面的内容是空的,那么就是执行else的内容了。
{{define "with"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body><h3>This is with</h3><table style="border-collapse:collapse;">{{with ""}} <tr > <td style="border:1px solid orange;">爱{{.}}</td> </tr>{{else}} <tr > <td style="border:1px solid orange;">原来的数据{{.}}</td> </tr>{{end}}</table></body></html>{{end}}
with内容为空的执行结果
with ""
如果你在模板中使用了 define 定义模板名,在代码中,就必须使用
t.ExecuteTemplate(writer,"arg", map[string]string{"星期一":"Monday"})这样的语法
参数、变量、管道
在go语言中,模板参数也可以是各种形式的值,比如:布尔值、整数、字符串、结构、结构中的一个字段、数组中的一个键、一个变量、一个方法(有且只有一个返回值或再加上一个返回错误)、一个函数、或者一个点(.)。
就好像这样的代码
{{if arg}} some content {{end}}
在动作中设置变量,是以美元符号$开头,就像这样:
$variable := value
这样看似乎变量没什么大用,但是,如果是下面这样呢?
{{range $key, $value := . }} Key = {{ $key }}; Value = {{ $value }} {{end}}
变量实际上对动作来说,是非常重要的。
参看示例代码
//参数、变量、管道func processArgHandler(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTempWeb/tmplArg.html") t.ExecuteTemplate(writer,"arg", map[string]string{"星期一":"Monday"}) }
这里的data是一个map映射,要传递到模板tmplArg.html组合后返回html代码。
模板代码
{{define "arg"}}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body><h3>This is Arg/value/channel</h3><table style="border-collapse:collapse;">{{range $key, $value := .}} <tr> <td style="border:1px solid orange;">Key = {{ $key }};Value = {{ $value }}</td> </tr>{{end}}</table><h3>This is include</h3></body></html>{{end}}
在main函数中加入下面的代码
http.HandleFunc("/processArg/", processArgHandler)
执行结果如下
参数、变量
这样写map当然在实际项目代码中不会这么弄了。那么,看一下这段代码
func Joeltemplate5(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTemplate/sayHelloDay.html") weekday := map[string]string{"Sunday":"星期日", "Monday":"星期一", "Tuesday":"星期二", "Wednesday":"星期三", "Thursday":"星期四", "Friday":"星期五", "Saturday":"星期六"} t.ExecuteTemplate(writer,"sayHelloDay.html", weekday) }
这样,就会随机的把map中的key 和 value 都显示出来了。而且,代码更符合实际编码的习惯。在给值前对map内的元素进行编辑。
模板中的管道是多个有序串联起来的参数。参数以 “|” 符号分隔。管道允许用户将一个参数的输出传递给下一个参数。比如,一个值为浮点数的参数,在模板中进行格式化,就像这样
{{ 2014.10171695 | printf "%.2f"}}
执行后,会得到 2014.10
代码如下
func Joeltemplate6(writer http.ResponseWriter, request *http.Request) { t, _ := template.ParseFiles("./JoelTemplate/sayHelloPipe.html") /*cmd1 := exec.Command("love","shun","sun") stdout1, err := cmd1.StdinPipe() if err != nil { t.ExecuteTemplate(writer, "sayHelloPipe.html", err) }else{ t.ExecuteTemplate(writer, "sayHelloPipe.html", stdout1) }*/ var nf float64 = 2014.10171695t.ExecuteTemplate(writer, "sayHelloPipe.html", nf) }
模板文件sayHelloPipe.html代码
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Go Web Programming</title></head><body> {{.|printf "%.2f"}}</body></html>
在main中 http.HandleFunc("/uu/", JoelTempFunc.Joeltemplate6)
然后就可以在 路径 uu 里看到执行结果了
%.2f
然后,我没知道实际的值在小数点后面还有很多位,当需要显示更大精度的浮点数的时候,不需要修改 go 代码,只修改模板文件里的通道参数就可以了。
{{.|printf "%.2f"}} 改为 {{.|printf "%.4f"}}
保存模板后,执行结果是
%.4f
作者:厚土火烟
链接:https://www.jianshu.com/p/e5736e618471
共同学习,写下你的评论
评论加载中...
作者其他优质文章