如何渲染多个模板
Posted
技术标签:
【中文标题】如何渲染多个模板【英文标题】:How to Render multiple templates 【发布时间】:2013-06-16 21:16:30 【问题描述】:创建一个基本模板。 有了这个呈现的 first.html 另一个模板。
eg. :
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/first.html",
))
但我还想添加更多 .html 文件进行渲染。 有参考吗?
【问题讨论】:
尝试添加第三个文件时出了什么问题? 【参考方案1】:如果您在模板文件夹中定义所有模板,您可以轻松地解析整个目录:
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"
)
// 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
你用templates.ExecuteTemplate(w, "indexPage", nil)
执行你的indexPage-Template
【讨论】:
:main.go : var templates template.Template templates = template.Must(template.ParseGlob("templates/.tmpl")) func init()http. HandleFunc("/", handler) func handler(w http.ResponseWriter, r *http.Request)templates.ExecuteTemplate(w, "indexPage", nil) 这个例子给出了错误 "expected declaration, found 'IDENT'模板” 你的声明是假的,应该是:var templates := template.Must(template.ParseGlob("templates/.tmpl/.*")) 我假设你所有的模板都在 templates/.tmpl/.* 目录中 我更新了这个答案以更正 typeos 和编译错误。 +1,因为这可以帮助我自己正确定义多个模板。起初并不清楚,因为我们大多数人来自 .net 和其他具有布局和模板的语言,您不会创建一个单一的母版和单一的内容区域,而是定义共享的页眉和页脚和侧边栏。这实际上很好,因为您可以在每个模板进程中控制是否显示侧边栏。 这应该是公认的答案。这个答案比文档清楚得多。它展示了如何使用全局templates
变量,以便您在服务器启动时加载所有模板,而不是在实际处理程序中(将在每次页面加载时加载)。它还展示了如何按名称定义模板,然后使用templates.ExecuteTemplate
调用它,这非常有用。到目前为止,我在这个主题上看到的最好的文档......【参考方案2】:
您只需将它们添加为参数即可轻松添加更多 .html 文件:
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/first.html",
"templates/second.html",
))
只要第一个和第二个不定义相同的模板,这工作正常。 但是,模板包不允许使用模板名称的管道值动态调用模板。因此,如果您尝试执行类似于我下面的示例的操作,那么它将无法正常工作。
存在一些解决方法,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 pageend`
const second = `define "second"And here is the secondend`
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)
Code on play.golang.org
【讨论】:
ANisus :如果我单击第一页按钮上的事件触发器,那么它应该呈现提到的其他页面......有 Redirect 和 renderTemplate 功能,但它们也不起作用。对于 base.html 和 first.html,我能够呈现页面。但是对于第三个 html 页面,它不起作用 @fmt.Fprint 我认为您需要为您的模板和处理程序获取一些结构。 Kyle Finley 对此有一个很好的建议:(***.com/a/9587616/694331) 这个链接已经试过了。 base.html 和 first.html 很好。但是第三个和第四个的问题 我对 golang 很陌生,但似乎问题归结为您不能将字符串类型的变量传递给template
方法,而只能传递字符串文字?我也不是 CS 人,Go 开发人员做出这个选择有明显的理由吗?我想这实际上是在此处的文档中:template "name" The template with the specified name is executed with nil data.
我只是没有发现他们正在写“名称”来暗示字符串文字而不是写 name string
。【参考方案3】:
如果你想用特定文件解析多个目录,这里有一个代码sn-p:
//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
快捷方式:
allTemplates := template.Must(
template.Must(
template.Must(
template.ParseGlob("directory/*.tmpl")).
ParseGlob("another_directory/*.tmpl")).
ParseFiles("path/to/file.tmpl")),
)
file.tmpl
可以是这样的:
<html>
This is a template file
</html>
name.tmpl
应该是这样的
define "handlerName"
<p>this is a handler</p>
end
【讨论】:
你测试了吗?syntax error: non-declaration statement outside function body
...
@FisNan 您是否尝试过改用var allTemplates = ...
。如果没有帮助,您仍然可以将所有代码放入 main()
func 中,答案让您大致了解如何操作.. 希望我的评论对您有所帮助,谢谢
我使用了一个全局空指针var allTemplates *template.Template
,然后将所有template.Must(...)
放入main
函数中。不过感谢您的回复!【参考方案4】:
本教程的第 3 部分很有用:
http://golangtutorials.blogspot.co.nz/2011/11/go-templates-part-3-template-sets.html
教程示例:
完整的模板文件 - t1.tmpl
define "t_ab"a btemplate "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("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 btemplate "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
【讨论】:
以上是关于如何渲染多个模板的主要内容,如果未能解决你的问题,请参考以下文章