模板是构建丰富结构的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 main
import (
"fmt"
"joeltest/JoelTempWeb"
)
func main() {
JoelTempWeb.JoelHttpPath()
JoelTempWeb.JoelListenAndServe()
}
完整JoelTempWeb代码
package JoelTempWeb
import (
"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内容为空的执行结果
参数、变量
这样写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.10171695
t.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
你也可以试试其他精度的表现。
网友评论