02-Template-Basic
学习完 第一章 之后,我们已经拥有了虽然一个简单,但可以成功运行Web应用
本章将沿用这个应用,在此之上,加入模版渲染,使得页面更丰富
本章的GitHub链接为: Source, Diff, Zip

什么是模板

微博应用程序的主页会有一个欢迎用户的标题。虽然目前的应用程序还没有实现用户概念,但这不妨碍我使用一个 Go Stuct 来模拟一个用户,由于Go是静态语言,先定义 User 的结构,然后再初始化 user ,如下所示:
1
type User struct {
2
Username string
3
}
4
5
user := User{Username: "bonfy"}
Copied!
创建模拟对象是一项实用的技术,它可以让你专注于应用程序的一部分,而无需为系统中尚不存在的其他部分分心。 在设计应用程序主页的时候,我可不希望因为没有一个用户系统来分散我的注意力,因此我使用了模拟用户对象,来继续接下来的工作。
原先的视图函数返回简单的字符串,我现在要将其扩展为包含完整HTML页面元素的字符串,如下所示:
1
package main
2
3
import (
4
"html/template"
5
"net/http"
6
)
7
8
// User struct
9
type User struct {
10
Username string
11
}
12
13
func main() {
14
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
15
user := User{Username: "bonfy"}
16
tpl, _ := template.New("").Parse(`<html>
17
<head>
18
<title>Home Page - Bonfy</title>
19
</head>
20
<body>
21
<h1>Hello, {{.Username}}!</h1>
22
</body>
23
</html>`)
24
tpl.Execute(w, &user)
25
})
26
http.ListenAndServe(":8888", nil)
27
}
Copied!
对HTML标记语言不熟悉的话,建议阅读一下Wikipedia上的简介HTML Markup
利用上述的代码更新这个视图函数,然后再次运行 (这里并没有flask那样子的debug mode,每次更新都必须重新执行)
1
$ go run main.go
Copied!
在浏览器打开它的URL看看结果
02-01
本小节 Diff
Tip: Go 中反引号用来创建原生的字符串字面量,这些字符串可能由多行组成(不支持任何转义序列),原生的字符串字面量多用于书写多行消息、HTML以及正则表达式
我们暂时将 template 以文本方式耦合在代码中,随着我们项目的扩大,这个不利于管理,而且如果公司有前端支持的话,模板的工作很大可能会有前端设计,所以我们有必要对其进行解偶。我们打算将模板文件放入 templates 的文件夹
建立 templates 文件夹
1
$ mkdir templates
Copied!
将模板的内容移到 templates文件夹下
templates/index.html
1
<html>
2
<head>
3
<title>Home Page - Bonfy</title>
4
</head>
5
<body>
6
<h1>Hello, {{.Username}}!</h1>
7
</body>
8
</html>
Copied!
然后将 template 文本从代码中移除
main.go
1
package main
2
3
import (
4
"html/template"
5
"net/http"
6
)
7
8
// User struct
9
type User struct {
10
Username string
11
}
12
13
func main() {
14
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
15
user := User{Username: "bonfy"}
16
tpl, _ := template.ParseFiles("templates/index.html")
17
tpl.Execute(w, &user)
18
})
19
http.ListenAndServe(":8888", nil)
20
}
Copied!
然后运行,在浏览器中打开,结果是与刚才一样的,不过代码的组织结构却更清晰了。
本小节 Diff

模板的常用操作

条件语句

在 index.html 中加入条件语句
templates/index.html
1
<html>
2
<head>
3
{{if .Title}}
4
<title>{{.Title}} - blog</title>
5
{{else}}
6
<title>Welcome to blog!</title>
7
{{end}}
8
</head>
9
<body>
10
<h1>Hello, {{.User.Username}}!</h1>
11
</body>
12
</html>
Copied!
由于 User 没有 Title字段,所以我们引入新的 IndexViewModel 来具体处理所有与View对应的Model
main.go
1
package main
2
3
import (
4
"html/template"
5
"net/http"
6
)
7
8
// User struct
9
type User struct {
10
Username string
11
}
12
13
// IndexViewModel struct
14
type IndexViewModel struct {
15
Title string
16
User User
17
}
18
19
func main() {
20
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
21
user := User{Username: "bonfy"}
22
v := IndexViewModel{Title: "Homepage", User: user}
23
tpl, _ := template.ParseFiles("templates/index.html")
24
tpl.Execute(w, &v)
25
})
26
http.ListenAndServe(":8888", nil)
27
}
Copied!
本小节 Diff

循环

在 index.html 中加入循环
1
<html>
2
<head>
3
{{if .Title}}
4
<title>{{.Title}} - blog</title>
5
{{else}}
6
<title>Welcome to blog!</title>
7
{{end}}
8
</head>
9
<body>
10
<h1>Hello, {{.User.Username}}!</h1>
11
{{range .Posts}}
12
<div><p>{{ .User.Username }} says: <b>{{ .Body }}</b></p></div>
13
{{end}}
14
</body>
15
</html>
Copied!
在 main.go 的 IndexViewModel 中加入 Post
1
package main
2
3
import (
4
"html/template"
5
"net/http"
6
)
7
8
// User struct
9
type User struct {
10
Username string
11
}
12
13
// Post struct
14
type Post struct {
15
User User
16
Body string
17
}
18
19
// IndexViewModel struct
20
type IndexViewModel struct {
21
Title string
22
User User
23
Posts []Post
24
}
25
26
func main() {
27
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
28
u1 := User{Username: "bonfy"}
29
u2 := User{Username: "rene"}
30
31
posts := []Post{
32
Post{User: u1, Body: "Beautiful day in Portland!"},
33
Post{User: u2, Body: "The Avengers movie was so cool!"},
34
}
35
36
v := IndexViewModel{Title: "Homepage", User: u1, Posts: posts}
37
tpl, _ := template.ParseFiles("templates/index.html")
38
tpl.Execute(w, &v)
39
})
40
http.ListenAndServe(":8888", nil)
41
}
Copied!
本小节 Diff
运行效果图
02-02

Links

Last modified 3yr ago