在不每次解析的情况下,将一个模板嵌套在另一个模板中进行渲染。

huangapple go评论81阅读模式
英文:

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:

&lt;h1&gt;Base.html rendered here&lt;/h1&gt;
{{template &quot;content&quot; .}}

view.html:

{{define &quot;content&quot;}}
...
{{end}}

edit.html:

{{define &quot;content&quot;}}
...
{{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(&quot;/edit&quot;, handlerEdit)
   http.HandleFunc(&quot;/view&quot;, handlerView)
   http.ListenAndServe(&quot;:8080&quot;, nil)
}
func handlerView(w http.ResponseWriter, req *http.Request) {
   renderTemplate(w, req, &quot;view&quot;)
}

func handlerEdit(w http.ResponseWriter, req *http.Request) {
   renderTemplate(w, req, &quot;edit&quot;)
}

func renderTemplate(w http.ResponseWriter, req *http.Request, tmpl    string) {
   templates, err := template.ParseFiles(&quot;templates/base.html&quot;,  &quot;templates/&quot;+tmpl+&quot;.html&quot;)
   if err != nil {
	   fmt.Println(&quot;Something goes wrong &quot;, err)
	   return
   }
   someData := &amp;Page{Title: &quot;QWE&quot;, Body: []byte(&quot;sample body&quot;)}
   templates.Execute(w, someData)
}

I was looking at the template.ParseGlobe(), in order to do something like this

var templates = template.Must(template.ParseGlob(&quot;templates/*.html&quot;))
... //and then somthing like this:
err := templates.ExecuteTemplate(w, tmpl+&quot;.html&quot;, 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(&quot;templates/*.html&quot;))

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&#39;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 &quot;viewContent&quot;}}
{{template &quot;templates/base.html&quot; .}}
...Current view.html template...
{{end}}

{{define &quot;editContent&quot;}}
{{template &quot;templates/base.html&quot; .}}
...Current edit.html template...
{{end}}

huangapple
  • 本文由 发表于 2015年9月10日 21:27:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/32503247.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定