英文:
How to Render multiple templates
问题
一个基本模板被创建。
使用该模板渲染first.html另一个模板。
例如:
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/first.html",
))
但我还想添加更多的.html文件进行渲染。
有任何参考吗?
英文:
One base template is created.
With that rendered first.html one more template.
eg. :
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/first.html",
))
But I also want to add more .html files to render.
Any reference?
答案1
得分: 86
如果您将所有模板定义在一个模板文件夹中,您可以使用以下代码轻松解析整个目录:
template.Must(template.ParseGlob("YOURDIRECTORY/*"))
例如:
head.html
{{define "header"}}
<head>
<title>Index</title>
</head>
{{end}}
index.html
{{define "indexPage"}}
<html>
{{template "header"}}
<body>
<h1>Index</h1>
</body>
</html>
{{end}}
main.go
package main
import(
"html/template"
)
// 编译所有模板并缓存它们
var templates = template.Must(template.ParseGlob("YOURTEMPLATEDIR/*"))
func main(){
...
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
// 您可以通过定义的名称而不是文件名访问缓存的模板
err := templates.ExecuteTemplate(w, "indexPage", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
您可以使用 templates.ExecuteTemplate(w, "indexPage", nil)
执行您的 indexPage 模板。
英文:
If you define all your templates in a template-folder, you can easily parse the whole directory with:
template.Must(template.ParseGlob("YOURDIRECTORY/*"))
For example:
head.html
{{define "header"}}
<head>
<title>Index</title>
</head>
{{end}}
index.html
{{define "indexPage"}}
<html>
{{template "header"}}
<body>
<h1>Index</h1>
</body>
</html>
{{end}}
main.go
package main
import(
"html/template"
)
// compile all templates and cache them
var templates = template.Must(template.ParseGlob("YOURTEMPLATEDIR/*"))
func main(){
...
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
// you access the cached templates with the defined name, not the filename
err := templates.ExecuteTemplate(w, "indexPage", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
You execute your indexPage-Template with templates.ExecuteTemplate(w, "indexPage", nil)
答案2
得分: 9
你可以通过将它们作为参数添加来轻松添加更多的.html文件:
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/first.html",
"templates/second.html",
))
只要first和second没有定义相同的模板,这个方法就可以正常工作。然而,模板包不允许使用管道值作为模板名称来动态调用模板。所以,如果你想要做类似于下面示例的事情,它将不起作用。
有一些解决方法,并且在Go-nuts上有关于它的讨论。但是似乎模板包的设计是你应该为每个页面拥有一个*Template
对象。
尝试动态模板调用的错误示例:
错误:在模板调用中出现意外的".Content"
package main
import (
"log"
"os"
"text/template"
)
const base= `<!DOCTYPE html>
<html>
<head><title>Title</title></head>
<body>
{{template .Content}}
</body>
</html>`
const first = `{{define "first"}}This is the first page{{end}}`
const second = `{{define "second"}}And here is the second{{end}}`
type View struct {
Content string
}
func main() {
var view = &View{ "first" } // Here we try to set which page to view as content
t := template.Must(template.New("base").Parse(base))
t = template.Must(t.Parse(first))
t = template.Must(t.Parse(second))
err := t.Execute(os.Stdout, view)
if err != nil {
log.Println("executing template:", err)
}
}
英文:
You can easily add more .html files by just adding them as arguments:
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/first.html",
"templates/second.html",
))
This works fine as long as first and second don't define the same template.
However, the template package does not allow dynamic invocation of templates, using a pipeline value for the template name. So, if you are trying to do something similar to my example below, then it will not work.
Some workarounds exists, and there is a discussion about it on Go-nuts. But it seems the template package is designed that you should have one *Template
object per page.
Broken example of attempted dynamic template invocation:
Error: unexpected ".Content" in template invocation
package main
import (
"log"
"os"
"text/template"
)
const base= `<!DOCTYPE html>
<html>
<head><title>Title</title></head>
<body>
{{template .Content}}
</body>
</html>`
const first = `{{define "first"}}This is the first page{{end}}`
const second = `{{define "second"}}And here is the second{{end}}`
type View struct {
Content string
}
func main() {
var view = &View{ "first" } // Here we try to set which page to view as content
t := template.Must(template.New("base").Parse(base))
t = template.Must(t.Parse(first))
t = template.Must(t.Parse(second))
err := t.Execute(os.Stdout, view)
if err != nil {
log.Println("executing template:", err)
}
}
答案3
得分: 3
如果您想解析多个目录以及特定文件,这里有一个代码片段:
// 解析特定目录中的模板
allTemplates := template.Must(template.ParseGlob("目录/*"))
// 添加另一个目录进行解析
allTemplates = template.Must(allTemplates.ParseGlob("另一个目录/*.tmpl"))
// 添加特定文件名
allTemplates = template.Must(allTemplates.ParseFiles("路径/到/文件.tmpl"))
func main() {
...
}
func FileHandler(w http.ResponseWriter, r *http.Request) {
// 通过文件名访问缓存的模板(如果您没有定义其名称)
err := allTemplates.ExecuteTemplate(w, "file.tmpl", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func NameHandler(w http.ResponseWriter, r *http.Request) {
// 通过处理程序名称访问缓存的模板
err := allTemplates.ExecuteTemplate(w, "handlerName", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
一个快捷方式:
allTemplates := template.Must(
template.Must(
template.Must(
template.ParseGlob("目录/*.tmpl")).
ParseGlob("另一个目录/*.tmpl")).
ParseFiles("路径/到/文件.tmpl"),
)
file.tmpl
可以是以下内容:
<html>
This is a template file
</html>
name.tmpl
应该是这样的:
{{define "handlerName" }}
<p>this is a handler</p>
{{end}}
英文:
If you want to parse multiple directories a long with specific files, here's a code snippet for it:
//parse a pattern in a specific directory
allTemplates := template.Must(template.ParseGlob("Directory/*"))
//add another directory for parsing
allTemplates = template.Must(allTemplates.ParseGlob("Another_Directory/*.tmpl"))
//add specific file name
allTemplates = template.Must(allTemplates.ParseFiles("path/to/file.tmpl"))
func main() {
...
}
func FileHandler(w http.ResponseWriter, r *http.Request) {
// access cached template by file name (in case you didn't define its name)
err := allTemplates.ExecuteTemplate(w, "file.tmpl", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func NameHandler(w http.ResponseWriter, r *http.Request) {
// access cached template by handler name
err := allTemplates.ExecuteTemplate(w, "handlerName", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
a quick shortcut:
allTemplates := template.Must(
template.Must(
template.Must(
template.ParseGlob("directory/*.tmpl")).
ParseGlob("another_directory/*.tmpl")).
ParseFiles("path/to/file.tmpl")),
)
file.tmpl
can be like the following:
<html>
This is a template file
</html>
name.tmpl
should be looking like this
{{define "handlerName" }}
<p>this is a handler</p>
{{end}}
答案4
得分: 2
这个教程的第三部分很有用:
http://golangtutorials.blogspot.co.nz/2011/11/go-templates-part-3-template-sets.html
教程中的示例:
完整的模板文件 - t1.tmpl
{{define "t_ab"}}a b{{template "t_cd"}}e f {{end}}
上面的文件将被解析为一个名为"t_ab"的模板。它包含了"a b /missing/ e f",但是在字母表中缺少了几个字母。为此,它打算包含另一个名为"t_cd"的模板(应该在同一个集合中)。
完整的模板文件 - t2.tmpl
{{define "t_cd"}} c d {{end}}
上面的文件将被解析为一个名为"t_cd"的模板。
完整的程序
package main
import (
"text/template"
"os"
"fmt"
)
func main() {
fmt.Println("加载一组带有{{define}}子句的模板并执行:")
s1, _ := template.ParseFiles("t1.tmpl", "t2.tmpl") //从多个文件创建一组模板。
//注意,t1.tmpl是内容为"{{define "t_ab"}}a b{{template "t_cd"}}e f {{end}}"的文件
//注意,t2.tmpl是内容为"{{define "t_cd"}} c d {{end}}"的文件
s1.ExecuteTemplate(os.Stdout, "t_cd", nil) //只打印c d
fmt.Println()
s1.ExecuteTemplate(os.Stdout, "t_ab", nil) //执行t_ab,它将包含t_cd
fmt.Println()
s1.Execute(os.Stdout, nil) //由于这个数据结构中的模板是有名字的,所以没有默认模板,所以什么也不打印
}
英文:
part 3 of this tutorial is useful:
http://golangtutorials.blogspot.co.nz/2011/11/go-templates-part-3-template-sets.html
Sample from the tutorial:
Full template file - t1.tmpl
{{define "t_ab"}}a b{{template "t_cd"}}e f {{end}}
The file above will be parsed in as a template named "t_ab". It has, within it, "a b /missing/ e f", but is missing a couple of letters in the alphabet. For that it intends to include another template called "t_cd" (which should be in the same set).
Full template file - t2.tmpl
{{define "t_cd"}} c d {{end}}
The file above will be parsed in as a template called "t_cd".
Full program
package main
import (
"text/template"
"os"
"fmt"
)
func main() {
fmt.Println("Load a set of templates with {{define}} clauses and execute:")
s1, _ := template.ParseFiles("t1.tmpl", "t2.tmpl") //create a set of templates from many files.
//Note that t1.tmpl is the file with contents "{{define "t_ab"}}a b{{template "t_cd"}}e f {{end}}"
//Note that t2.tmpl is the file with contents "{{define "t_cd"}} c d {{end}}"
s1.ExecuteTemplate(os.Stdout, "t_cd", nil) //just printing of c d
fmt.Println()
s1.ExecuteTemplate(os.Stdout, "t_ab", nil) //execute t_ab which will include t_cd
fmt.Println()
s1.Execute(os.Stdout, nil) //since templates in this data structure are named, there is no default template and so it prints nothing
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论