Go 视图模板篇(二):通过指令实现控制结构和模板引入
指令用于在 Go 模板中嵌入命令,通过 {{
和 }}
来定义,Go 提供了丰富的指令集,包括条件判断、循环、设置和引入等。
在众多 Go 模板指令中,.
是最重要的一个,它用于解析传递到模板的数据,其他指令和函数大多都是围绕这个 .
进行格式化和显示。
条件指令
要在视图模板中使用 if 条件判断,可以这么做:
{{ if arg }}
some content
{{ end }}
还可以编写 if...else... 控制结构语句:
{{ if arg }}
some content
{{ else }}
other content
{{ end }}
其中 arg
可以是常量、变量、或者返回某个值的函数或方法。
下面看一个简单的示例,编写服务端处理器代码如下:
package main
import (
"html/template"
"math/rand"
"net/http"
"time"
)
func process(w http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("condition.html"))
rand.Seed(time.Now().Unix())
t.Execute(w, rand.Intn(10) > 5)
}
func main() {
http.HandleFunc("/condition", process)
http.ListenAndServe(":8080", nil)
}
对应的模板代码 condition.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Condition Actions</title>
</head>
<body>
{{ if . }}
Number is greater than 5!
{{ else }}
Number is less than or equal to 5!
{{ end }}
</body>
</html>
运行服务端代码启动服务器,在终端窗口通过 curl 请求 /condition
路由,可以看到对应的返回结果如下:
迭代指令
迭代指令可以用于循环迭代数组、切片、字典和通道:
{{ range array }}
Dot is set to the element {{ . }}
{{ end }}
编写一段服务端处理器示例代码如下:
package main
import (
"html/template"
"net/http"
)
func iterationActionExample( w http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("iteration.html"))
daysOfWeek := []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
t.Execute(w, daysOfWeek)
}
func main() {
http.HandleFunc("/iteration", iterationActionExample)
http.ListenAndServe(":8080", nil)
}
以及对应的模板代码 iteration.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Iteration Actions</title>
</head>
<body>
<ul>
{{ range . }}
<li>{{ . }}</li>
{{ end }}
</ul>
</body>
</html>
运行服务端代码启动服务器,在浏览器访问 http://localhost:8080/iteration
,输出结果如下:
可以看到无论是外层的循环体,还是循环体内部的元素,都是通过 .
来替代。如果待迭代的变量为空的话,还可以通过下面这种方式来处理:
<ul>
{{ range . }}
<li>{{ . }}</li>
{{ else }}
<p>Nothing to show</p>
{{ end }}
</ul>
设置指令
此外,在 Go 模板中,还可以通过 with
指令设置变量值:
{{ with arg }}
Dot is set to arg
{{ end }}
这样一来,在 {{ with arg }}
和 {{ end }}
之间的 .
会被设置为 arg
。
我们编写一段示例代码进行演示,对应的服务端处理器代码如下:
package main
import (
"html/template"
"net/http"
)
func setActionExample(w http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("set.html"))
t.Execute(w, "golang")
}
func main() {
http.HandleFunc("/set_action", setActionExample)
http.ListenAndServe(":8080", nil)
}
对应的模板文件 set.html
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Set Action</title>
</head>
<body>
<div>The dot is {{ . }}</div>
<div>
{{ with "php" }}
Now the dot is set to {{ . }}
{{ end }}
</div>
<div>The dot is {{ . }} again</div>
</body>
</html>
运行服务端代码启动服务器,在浏览器中访问 http://localhost:8080/set_action
,返回结果如下:
同样,设置指令也支持 else
:
{{ with arg }}
Dot is set to arg
{{ else }}
Fallback if arg is empty
{{ end }}
其含义是如果 arg
值为空,则调用 else
区块对应的逻辑,例如:
{{ with "" }}
Dot is set to {{ . }}
{{ else }}
Dot is still {{ . }}
{{ end }}
引入指令
最后,我们还可以通过引入指令来嵌入子模板:
{{ template "name" }}
我们编写一段服务端处理器示例代码如下,这里我们解析了两个模板文件,其中 t1.html
是主模板,t2.html
是前者引入的子模板:
package main
import (
"html/template"
"net/http"
)
func includeActionExample(w http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("t1.html", "t2.html"))
t.Execute(w, "Hello World!")
}
func main() {
http.HandleFunc("/include", includeActionExample)
http.ListenAndServe(":8080", nil)
}
对应的模板文件 t1.html
代码(主模板,通过 template
指令引入子模板 t2.html
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Template 1</title>
</head>
<body>
<div> This is t1.html before </div>
<div> This is the value of the dot in t1.html - [{{ . }}] </div>
<hr/>
{{ template "t2.html" }}
<hr/>
<div> This is t1.html after </div>
</body>
</html>
以及模板文本 t2.html
代码(这是一个子模板):
<div style="background-color: yellow;">
This is t2.html
<br/>
This is the value of the dot in t2.html - [{{ . }}]
</div>
运行服务端代码启动服务器,在浏览器中访问 http://localhost:8080/include
,输出结果如下:
可以看到嵌套模板中的变量值为空,这是因为我们没有从第一个模板将变量传入第二个模板,如果要传入的话可以这么做:
{{ template "t2.html" . }}
这样就可以在嵌套模板中看到这个值了:
No Comments