如何渲染多个模板

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

【讨论】:

以上是关于如何渲染多个模板的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 具有相同模板的多个路由不应重新渲染

在 Flask 中一次渲染多个模板

使用渲染将多个对象传递给模板

在 spring-boot 中使用一个模板引擎渲染多个后缀

如何在 Django 中将多个上下文呈现为相同的 HTML

Django 多模板渲染