65.模板详细使用(一)

作者: 厚土火焱 | 来源:发表于2018-09-08 19:05 被阅读34次

模板是构建丰富结构的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内容为空的执行结果

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

你也可以试试其他精度的表现。

相关文章

网友评论

    本文标题:65.模板详细使用(一)

    本文链接:https://www.haomeiwen.com/subject/eneyiftx.html