• 02-Template Basic
    • 什么是模板
    • 模板的常用操作
      • 条件语句
      • 循环
    • Links

    02-Template Basic

    学习完 第一章 之后,你已经拥有了一个简单,不过可以成功运行Web应用

    本章将沿用这个应用,在此之上,加入模版渲染,使得页面更丰富

    本章的GitHub链接为: Source, Diff,
    Zip

    什么是模板

    微博应用程序的主页会有一个欢迎用户的标题。虽然目前的应用程序还没有实现用户概念,但这不妨碍我使用一个 Go Stuct 来模拟一个用户,由于Go是静态语言,先定义 User 的结构,然后再初始化 user ,如下所示:

    1. type User struct {
    2. Username string
    3. }
    4. user := User{Username: "bonfy"}

    创建模拟对象是一项实用的技术,它可以让你专注于应用程序的一部分,而无需为系统中尚不存在的其他部分分心。 在设计应用程序主页的时候,我可不希望因为没有一个用户系统来分散我的注意力,因此我使用了模拟用户对象,来继续接下来的工作。

    原先的视图函数返回简单的字符串,我现在要将其扩展为包含完整HTML页面元素的字符串,如下所示:

    1. package main
    2. import (
    3. "html/template"
    4. "net/http"
    5. )
    6. // User struct
    7. type User struct {
    8. Username string
    9. }
    10. func main() {
    11. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    12. user := User{Username: "bonfy"}
    13. tpl, _ := template.New("").Parse(`<html>
    14. <head>
    15. <title>Home Page - Bonfy</title>
    16. </head>
    17. <body>
    18. <h1>Hello, {{.Username}}!</h1>
    19. </body>
    20. </html>`)
    21. tpl.Execute(w, &user)
    22. })
    23. http.ListenAndServe(":8888", nil)
    24. }

    对HTML标记语言不熟悉的话,建议阅读一下Wikipedia上的简介HTML Markup

    利用上述的代码更新这个视图函数,然后再次运行 (这里并没有flask那样子的debug mode,每次更新都必须重新执行)

    1. $ go run main.go

    在浏览器打开它的URL看看结果

    02-01

    本小节 Diff

    我们暂时将 template 以文本方式耦合在代码中,随着我们项目的扩大,这个不利于管理,而且如果公司有前端支持的话,模板的工作很大可能会有前端设计,所以我们有必要对其进行解偶。我们打算将模板文件放入 templates 的文件夹

    建立 templates 文件夹

    1. $ mkdir templates

    将模板的内容移到 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>

    然后将 template 文本从代码中移除

    main.go

    1. package main
    2. import (
    3. "html/template"
    4. "net/http"
    5. )
    6. // User struct
    7. type User struct {
    8. Username string
    9. }
    10. func main() {
    11. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    12. user := User{Username: "bonfy"}
    13. tpl, _ := template.ParseFiles("templates/index.html")
    14. tpl.Execute(w, &user)
    15. })
    16. http.ListenAndServe(":8888", nil)
    17. }

    然后运行,在浏览器中打开,结果是与刚才一样的,不过代码的组织结构却更清晰了。

    本小节 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>

    由于 User 没有 Title字段,所以我们引入新的 IndexViewModel 来具体处理所有与View对应的Model

    main.go

    1. package main
    2. import (
    3. "html/template"
    4. "net/http"
    5. )
    6. // User struct
    7. type User struct {
    8. Username string
    9. }
    10. // IndexViewModel struct
    11. type IndexViewModel struct {
    12. Title string
    13. User User
    14. }
    15. func main() {
    16. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    17. user := User{Username: "bonfy"}
    18. v := IndexViewModel{Title: "Homepage", User: user}
    19. tpl, _ := template.ParseFiles("templates/index.html")
    20. tpl.Execute(w, &v)
    21. })
    22. http.ListenAndServe(":8888", nil)
    23. }

    本小节 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>

    在 main.go 的 IndexViewModel 中加入 Post

    1. package main
    2. import (
    3. "html/template"
    4. "net/http"
    5. )
    6. // User struct
    7. type User struct {
    8. Username string
    9. }
    10. // Post struct
    11. type Post struct {
    12. User User
    13. Body string
    14. }
    15. // IndexViewModel struct
    16. type IndexViewModel struct {
    17. Title string
    18. User User
    19. Posts []Post
    20. }
    21. func main() {
    22. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    23. u1 := User{Username: "bonfy"}
    24. u2 := User{Username: "rene"}
    25. posts := []Post{
    26. Post{User: u1, Body: "Beautiful day in Portland!"},
    27. Post{User: u2, Body: "The Avengers movie was so cool!"},
    28. }
    29. v := IndexViewModel{Title: "Homepage", User: u1, Posts: posts}
    30. tpl, _ := template.ParseFiles("templates/index.html")
    31. tpl.Execute(w, &v)
    32. })
    33. http.ListenAndServe(":8888", nil)
    34. }

    本小节 Diff

    运行效果图

    02-02

    • 目录
    • 上一节: 01-Hello-World
    • 下一节: 03-Template-Advance