英文:
Render one template inside another without parsing them every time
问题
我有三个类似这样的模板:
base.html:
<h1>在这里呈现base.html</h1>
{{template "content" .}}
view.html:
{{define "content"}}
...
{{end}}
edit.html:
{{define "content"}}
...
{{end}}
我将它们存储在名为"templates"的文件夹中。
我想要的是在{{template "content" .}}的位置动态更改要呈现的模板,而不需要每次解析。所以我不想要这样的代码:
func main() {
http.HandleFunc("/edit", handlerEdit)
http.HandleFunc("/view", handlerView)
http.ListenAndServe(":8080", nil)
}
func handlerView(w http.ResponseWriter, req *http.Request) {
renderTemplate(w, req, "view")
}
func handlerEdit(w http.ResponseWriter, req *http.Request) {
renderTemplate(w, req, "edit")
}
func renderTemplate(w http.ResponseWriter, req *http.Request, tmpl string) {
templates, err := template.ParseFiles("templates/base.html", "templates/"+tmpl+".html")
if err != nil {
fmt.Println("Something goes wrong ", err)
return
}
someData := &Page{Title: "QWE", Body: []byte("sample body")}
templates.Execute(w, someData)
}
我看了一下template.ParseGlobe(),想要做这样的事情:
var templates = template.Must(template.ParseGlob("templates/*.html"))
... //然后像这样:
err := templates.ExecuteTemplate(w, tmpl+".html", p)
但是ExecuteTamplate()只接收一个字符串作为模板的名称。在这种情况下,我如何呈现两个或更多的模板?
英文:
I have three templates like this:
base.html:
<h1>Base.html rendered here</h1>
{{template "content" .}}
view.html:
{{define "content"}}
...
{{end}}
edit.html:
{{define "content"}}
...
{{end}}
I store them in folder "templates".
What i want is to dynamically change template which will be rendered in {{template "content" .}} place, without parsing every time. So what i DO NOT want is this :
func main() {
http.HandleFunc("/edit", handlerEdit)
http.HandleFunc("/view", handlerView)
http.ListenAndServe(":8080", nil)
}
func handlerView(w http.ResponseWriter, req *http.Request) {
renderTemplate(w, req, "view")
}
func handlerEdit(w http.ResponseWriter, req *http.Request) {
renderTemplate(w, req, "edit")
}
func renderTemplate(w http.ResponseWriter, req *http.Request, tmpl string) {
templates, err := template.ParseFiles("templates/base.html", "templates/"+tmpl+".html")
if err != nil {
fmt.Println("Something goes wrong ", err)
return
}
someData := &Page{Title: "QWE", Body: []byte("sample body")}
templates.Execute(w, someData)
}
I was looking at the template.ParseGlobe(), in order to do something like this
var templates = template.Must(template.ParseGlob("templates/*.html"))
... //and then somthing like this:
err := templates.ExecuteTemplate(w, tmpl+".html", p)
But ExecuteTamplate() recieves only one string as template's name. How in this case i can render two and more templates?
答案1
得分: 2
而不是直接写入http.ResponseWriter
,在调用ExecuteTemplate
时,可以先写入一个字节缓冲区,然后通过使用template.HTML
调用将其传递给下一个模板。
var b bytes.Buffer
var templates = template.Must(template.ParseGlob("templates/*.html"))
err := templates.ExecuteTemplate(&b, templ_1, p)
if err != nil { //处理错误 }
err := templates.ExecuteTemplate(w, templ_2, template.HTML(b.String()))
if err != nil { //处理错误 }
如果要使用未知数量的模板,可以使用字符串来捕获中间步骤:
var strtmp string
err := templates.ExecuteTemplate(&b, templ_1, p)
if err != nil { //处理错误 }
strtemp = b.String() //存储输出
b.Reset() //准备缓冲区以供下一个模板的输出使用
err := templates.ExecuteTemplate(&b, templ_2, template.HTML(strtmp))
if err != nil { //处理错误 }
//... 直到应用所有模板
b.WriteTo(w) //将最终输出发送到ResponseWriter
编辑:正如@Zhuharev指出的,如果视图和编辑模板的组合是固定的,它们都可以引用base,而不是base试图提供对视图或编辑的引用:
{{define "viewContent"}}
{{template "templates/base.html" .}}
...当前view.html模板...
{{end}}
{{define "editContent"}}
{{template "templates/base.html" .}}
...当前edit.html模板...
{{end}}
英文:
Instead of writing directly to the http.ResponseWriter
on your call to ExecuteTemplate
, write to a byte buffer and send that through the call to the next template by prepping it with a template.HTML
call.
var b bytes.Buffer
var templates = template.Must(template.ParseGlob("templates/*.html"))
err := templates.ExecuteTemplate(b, templ_1, p)
if err != nil { //handle err }
err := templates.ExecuteTemplate(w, templ_2, template.HTML(b.String()))
if err != nil { //handle err }
If you're going to use an unknown number of templates, you can capture the intermediate step with a string:
var strtmp string
err := templates.ExecuteTemplate(b, templ_1, p)
if err != nil { //handle err }
strtemp = b.String() //store the output
b.Reset() //prep buffer for next template's output
err := templates.ExecuteTemplate(b, templ_2, template.HTML(strtmp))
if err != nil { //handle err }
//... until all templates are applied
b.WriteTo(w) //Send the final output to the ResponseWriter
EDIT: As @Zhuharev pointed out, if the composition of the view and edit templates are fixed, they can both reference base rather than base trying to provide a reference to either view or edit:
{{define "viewContent"}}
{{template "templates/base.html" .}}
...Current view.html template...
{{end}}
{{define "editContent"}}
{{template "templates/base.html" .}}
...Current edit.html template...
{{end}}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论