引言
之前的文章学过把模板和视图拆散,建设一个 Web 服务器来展示 HTML 模板。咱们将学习如何应用 Go 的模板包创立动静 HTML 和文本文件。
建设 Web 服务器
到目前为止,咱们始终在向终端输入模板,然而当咱们开始深入研究更多 HTML 时,这开始变得不那么有意义了。相同,咱们心愿可视化在 Web 浏览器中生成的 HTML。为此,咱们首先须要设置一个 Web 服务器来出现咱们的 HTML 模板。
package main
import (
"html/template"
"net/http"
)
var testTemplate *template.Template
type ViewData struct {Name string}
func main() {
var err error
testTemplate, err = template.ParseFiles("hello.gohtml")
if err != nil {panic(err)
}
http.HandleFunc("/", handler)
http.ListenAndServe(":8000", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "text/html")
vd := ViewData{"Kyrie Jobs"}
err := testTemplate.Execute(w, vd)
if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
创立一个名为 hello.gohtml
的文件并将以下内容增加到其中:
<h1>Hello, {{.Name}}!</h1>
当初通过在终端中输出 go run main.go
来启动服务器。该程序应放弃运行并在端口 8000 上侦听 Web 申请,因而您能够在 localhost:8000
查看出现的 HTML。
if…else 块
咱们以后的模板很无聊,因为它只打印出一个人的名字。然而如果没有提供名字会产生什么?
让咱们试试看。关上你的 main.go
文件并删除你的 handler()
函数中创立 ViewData
实例的代码,而是向 testTemplate.Execute
办法提供 nil。实现后,您的 handler()
函数应如下所示:
func handler(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "text/html")
err := testTemplate.Execute(w, nil)
if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
当初重新启动您的服务器(或让新服务器重新启动)并在浏览器中拜访该页面 – localhost:8000
。您应该看到一个看起来像这样的页面。
当咱们不提供名称时,模板将应用空字符串代替值出现。相同,咱们心愿咱们的页面显示一个更通用的字符串,例如“Hello, there!”。让咱们持续更新模板以应用咱们的第一个操作,即 if/else
块。像这样更新 hello.gohtml
:
<h1>Hello, {{if .Name}} {{.Name}} {{else}} there {{end}}!</h1>
如果您在浏览器中查看该页面,您应该会看到这更新了您的模板以显示“Hello, there !”就像咱们想要的那样,但可怜的是,这在“there”这个词和感叹号之间减少了一个额定的空格。大多数时候这并不重要,然而在解决文本时,这有时会很烦人。在下一节中,咱们将看看两个选项来略微清理一下。
为了解脱额定的空白,咱们有几个抉择:
- 从咱们的模板中删除它们。
- 应用减号 (
-
) 通知模板包修剪多余的空白。
第一个选项非常简单。咱们只需将 hello.gohtml
文件更新为并删除多余的空格。
<h1>Hello, {{if .Name}}{{.Name}}{{else}}there{{end}}!</h1>
在这个例子中,这很好用,因为它是一段十分短的文本,然而设想一下咱们正在生成 python 代码,其中间距很重要 – 这很快就会变得十分烦人。侥幸的是,模板包还提供了一种应用减号来修剪不须要的空白的办法。
<h1>
Hello,
{{if .Name}}
{{.Name}}
{{- else}}
there
{{- end}}!
</h1>
在此代码片段中,咱们通过将减号字符放在 else 关键字的后面来通知模板包,咱们不心愿 Name 变量及其前面的任何内容之间的所有空格,并且咱们也对 end 执行雷同操作倒数第二行的关键字。从新加载您的页面,您应该会看到该空格不再存在。
对于本教程的其余部分,我将抉择应用此处的第一个示例作为我的 hello.html
文件。
范畴块
当初让咱们假如您想在您的网站上显示所有小部件以及它们的价格。这是动静 Web 应用程序的工作类型,因为没有人违心为您销售的每件商品手动创立 HTML 并保护它。相同,咱们心愿对每个我的项目应用雷同的 HTML。在 Go 中,您能够应用模板内的范畴块来实现此目标。
{{range .Widgets}}
<div class="widget">
<h3 class="name">{{.Name}}</h3>
<span class="price">${{.Price}}</span>
</div>
{{end}}
如果你重启你的服务器(或者让新的)并在 localhost:8000
从新加载页面,你当初应该会看到一个 HTML 页面,其中显示了三个小部件,每个小部件都有一个题目和一个价格。如果咱们在数组中增加更多小部件,咱们会在这里看到更多,如果咱们将其保留为空数组,咱们将不会在此处看到任何小部件。
与 range
操作混同的最常见起源是咱们正在拜访小部件的各个属性,而无需在 .Widgets
值内应用索引或任何其余拜访器。这是因为范畴操作会将汇合中每个对象的值设置为范畴块内的点 (.
)。例如,如果您要在范畴块内渲染 {{.}}
,您将看到与在 Widget 对象上应用 fmt.Println()
雷同的输入。
嵌套模板
随着您的模板开始增长,您会很快发现您须要在不同的中央重用组件。这就是嵌套模板来援救这一天的中央。应用 Go 的模板包,您能够申明多个惟一命名的模板,而后当您须要在代码中应用另一个模板时,您只需应用 template 关键字援用它。例如,假如您想为您的网站申明一个页脚,您能够将其蕴含在多个页面和多个布局中。将以下页脚模板增加到 hello.html
文件中。你把它放在哪里并不重要,但我更喜爱把它放在文件的顶部。
{{define "footer"}}
<footer>
<p>
Copyright 2016 Calhoun.io
</p>
<p>
Contact information: <a href="mailto:jon@calhoun.io">jon@calhoun.io</a>.
</p>
</footer>
{{end}}
而后在小部件的范畴块之后插入以下行。
{{template "footer"}}
您的 hello.gohtml
文件应如下所示:
{{define "footer"}}
<footer>
<p>
Copyright 2016 Calhoun.io
</p>
<p>
Contact information: <a href="mailto:jon@calhoun.io">jon@calhoun.io</a>.
</p>
</footer>
{{end}}
{{range .Widgets}}
<div class="widget">
<h3 class="name">{{.Name}}</h3>
<span class="price">${{.Price}}</span>
</div>
{{end}}
{{template "footer"}}
当初,如果您查看 localhost:8000
,您将看到该页面正在应用您定义的页脚模板。当您定义一个模板时,您能够在任何其余模板中应用它,甚至能够屡次应用它。尝试蕴含页脚模板两次以理解我的意思。
模板变量
咱们的上一个示例很棒,然而当您须要在嵌套模板中蕴含一些数据时会产生什么?侥幸的是,模板操作容许您传入第二个参数,该参数将调配给模板内的点 (.
) 参数。例如,假如咱们想为小部件的名称题目局部编写模板,咱们能够应用以下代码来实现。
{{define "widget-header"}}
<h3 class="name">{{.}}</h3>
{{end}}
{{range .Widgets}}
<div class="widget">
{{template "widget-header" .Name}}
<span class="price">${{.Price}}</span>
</div>
{{end}}
在这种状况下,.Name
属性被调配给 widget-header 模板内的点 (.
) 属性。
带有模板变量的嵌套模板甚至容许您深刻多层,这意味着能够从模板外部调用模板。
{{define "widget"}}
<div class="widget">
{{template "widget-header" .Name}}
<span class="price">${{.Price}}</span>
</div>
{{end}}
{{define "widget-header"}}
<h3 class="name">{{.}}</h3>
{{end}}
{{range .Widgets}}
{{template "widget" .}}
{{end}}
这段代码的最终后果是雷同的,然而当初咱们有了一个小部件模板,咱们能够轻松地在 Web 应用程序的其余页面上重用它,而无需重写代码。
接下来
凭借您新学到的模板技能,您应该能够创立可重用的动静模板。在下一篇文章中,咱们将介绍如何应用内置的模板函数,如 and
、eq
、index
,而后咱们将看看如何增加咱们本人的自定义函数。我本来打算包含那些听到的,但这篇文章有很多要介绍的口头,我不想卖空任何一个。
在对于函数的帖子之后,咱们将介绍如何应用模板来创立 Web 应用程序的视图层。这将包含创立共享布局、定义能够被笼罩的默认模板,以及在不同页面中蕴含雷同的模板,而无需将所有代码放入单个文件中。
如果您感到雄心勃勃或好奇,您还能够查看 text/template
和 html/template
的模板文档。持续本人摸索其余一些常识~