【问题标题】: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 文件进行渲染。 有参考吗?

【问题讨论】:

  • 尝试添加第三个文件时出了什么问题?

标签: google-app-engine go


【解决方案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 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)
    }
}

Code on play.golang.org

【讨论】:

  • ANisus :如果我单击第一页按钮上的事件触发器,那么它应该呈现提到的其他页面......有 Redirect 和 renderTemplate 功能,但它们也不起作用。对于 base.html 和 first.html,我能够呈现页面。但是对于第三个 html 页面,它不起作用
  • @fmt.Fprint 我认为您需要为您的模板和处理程序获取一些结构。 Kyle Finley 对此有一个很好的建议:(stackoverflow.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 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("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 b{{template "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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 2016-11-13
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多