如何渲染多个模板

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

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(&quot;YOURDIRECTORY/*&quot;))

For example:

head.html

{{define &quot;header&quot;}}
     &lt;head&gt;
         &lt;title&gt;Index&lt;/title&gt;
     &lt;/head&gt;
{{end}}

index.html

{{define &quot;indexPage&quot;}}
    &lt;html&gt;
    {{template &quot;header&quot;}}
    &lt;body&gt;
        &lt;h1&gt;Index&lt;/h1&gt;
    &lt;/body&gt;
    &lt;/html&gt;
{{end}}

main.go

package main

import(
    &quot;html/template&quot;
)

// compile all templates and cache them
var templates = template.Must(template.ParseGlob(&quot;YOURTEMPLATEDIR/*&quot;))

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, &quot;indexPage&quot;, nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

You execute your indexPage-Template with templates.ExecuteTemplate(w, &quot;indexPage&quot;, 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)
	}
}

在play.golang.org上的代码

英文:

You can easily add more .html files by just adding them as arguments:

var tmpl = template.Must(template.ParseFiles(
    &quot;templates/base.html&quot;,
    &quot;templates/first.html&quot;,
    &quot;templates/second.html&quot;,
))

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 (
	&quot;log&quot;
	&quot;os&quot;
	&quot;text/template&quot;
)

const base= `&lt;!DOCTYPE html&gt;
&lt;html&gt;
	&lt;head&gt;&lt;title&gt;Title&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
	{{template .Content}}
&lt;/body&gt;
&lt;/html&gt;`

const first = `{{define &quot;first&quot;}}This is the first page{{end}}`
const second = `{{define &quot;second&quot;}}And here is the second{{end}}`

type View struct {
	Content  string
}

func main() {
	var view = &amp;View{ &quot;first&quot; } // Here we try to set which page to view as content
	t := template.Must(template.New(&quot;base&quot;).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(&quot;executing template:&quot;, err)
	}
}

Code on play.golang.org

答案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(&quot;Directory/*&quot;))

//add another directory for parsing 
allTemplates = template.Must(allTemplates.ParseGlob(&quot;Another_Directory/*.tmpl&quot;))

//add specific file name 
allTemplates = template.Must(allTemplates.ParseFiles(&quot;path/to/file.tmpl&quot;))


func main() {
 ...
}

func FileHandler(w http.ResponseWriter, r *http.Request) {

    // access cached template by file name (in case you didn&#39;t define its name) 
    err := allTemplates.ExecuteTemplate(w, &quot;file.tmpl&quot;, 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, &quot;handlerName&quot;, nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

a quick shortcut:

allTemplates := template.Must(
		template.Must(
		template.Must(
			template.ParseGlob(&quot;directory/*.tmpl&quot;)).
			ParseGlob(&quot;another_directory/*.tmpl&quot;)).
			ParseFiles(&quot;path/to/file.tmpl&quot;)),
                )

file.tmpl can be like the following:

&lt;html&gt;
This is a template file 
&lt;/html&gt;

name.tmpl should be looking like this

{{define &quot;handlerName&quot; }}
&lt;p&gt;this is a handler&lt;/p&gt;
{{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 &quot;t_ab&quot;}}a b{{template &quot;t_cd&quot;}}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 &quot;t_cd&quot;}} c d {{end}}

The file above will be parsed in as a template called "t_cd".

Full program

package main

import (
    &quot;text/template&quot;
    &quot;os&quot;
    &quot;fmt&quot;
    )

func main() {
    fmt.Println(&quot;Load a set of templates with {{define}} clauses and execute:&quot;)
    s1, _ := template.ParseFiles(&quot;t1.tmpl&quot;, &quot;t2.tmpl&quot;) //create a set of templates from many files.
    //Note that t1.tmpl is the file with contents &quot;{{define &quot;t_ab&quot;}}a b{{template &quot;t_cd&quot;}}e f {{end}}&quot;
    //Note that t2.tmpl is the file with contents &quot;{{define &quot;t_cd&quot;}} c d {{end}}&quot;


    s1.ExecuteTemplate(os.Stdout, &quot;t_cd&quot;, nil) //just printing of c d
    fmt.Println()
    s1.ExecuteTemplate(os.Stdout, &quot;t_ab&quot;, 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
}

huangapple
  • 本文由 发表于 2013年6月20日 14:12:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/17206467.html
匿名

发表评论

匿名网友

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

确定