如何在 Go 中将模板呈现为多个布局?

How to render templates to multiple layouts in Go?

我需要将模板呈现为不同类型的布局。这是我的目录结构。

myapp
|
│   main.go
│
├───static
│       script.js
│       style.css
│
└───templates
    │   page1.tmpl
    │   page2.tmpl
    │   page3.tmpl
    │   page4.tmpl
    │   page5.tmpl
    │
    └───layouts
            base1.tmpl
            base2.tmpl
            base3.tmpl

我已经将模板渲染到单个布局模板,但是我无法让它在多个布局上工作。这是我到目前为止得到的:

package main

import (
    "html/template"
    "net/http"
    "fmt"
    "github.com/urfave/negroni"
    "github.com/oxtoacart/bpool"
    "path/filepath"
    "log"
)

var (
    templates        map[string]*template.Template
    bufpool          *bpool.BufferPool
)

func main() {
    loadTemplates()
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        renderTemplate(w, "page1.tmpl",nil)
    })
    n := negroni.New()
    n.Use(negroni.NewLogger())
    n.UseHandler(mux)
    http.ListenAndServe(":8080", n)
}

func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
    tmpl, ok := templates[name]
    if !ok {
        return fmt.Errorf("The template %s does not exist.", name)
    }

    buf := bufpool.Get()
    defer bufpool.Put(buf)

    err := tmpl.ExecuteTemplate(buf, "base1.tmpl", data)
    if err != nil {
        return err
    }

    w.Header().Set("Content-Type", "text/html; charset=utf-8")
    buf.WriteTo(w)
    return nil
}

func loadTemplates() {
    if templates == nil {
        templates = make(map[string]*template.Template)
    }

    tmplDir := "templates/"

    layouts, err := filepath.Glob(tmplDir + "layouts/*.tmpl")
    if err != nil {
        log.Fatal(err)
    }

    includes, err := filepath.Glob(tmplDir + "*.tmpl")
    if err != nil {
        log.Fatal(err)
    }

    for _, include := range includes {
        files := append(layouts, include)
        templates[filepath.Base(include)] = template.Must(template.ParseFiles(files...))
    }
    fmt.Print(includes)
    bufpool = bpool.NewBufferPool(64)
}

下面是 base1.tmpl 的样子:

{{define "base1"}}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{block "title" .}}{{end}}</title>
</head>
<body>
{{template "content" .}}
</body>
</html>
{{end}}

下面是 page1.tmpl 的样子:

{{define "title"}}Page 1{{end}}

{{define "content"}}
<p>Page 1 contents</p>
{{end}}

我通常采用渲染两次的方法,一次用于内容,一次用于布局,这使您可以在任何布局中使用任何内容,并将该决定推迟到运行时。如果其他人以不同的方式做,会对其他方法感兴趣,但这目前对我有用。

所以使用您发布的代码,在处理程序中是这样的:

data := map[string]interface{}{
            "title": "hello world",
        }
renderTemplate(w, "base1.tmpl", "page1.tmpl", data)

...

在 renderTemplate 中传递布局和模板,并且:

// Render the template 'name' with data
buf := bufpool.Get()
err := tmpl.ExecuteTemplate(buf, name, data)
if err != nil {
    return err
}

// Set the content as a key on data (set as html as it is rendered)
data["content"] = template.HTML(buf.Bytes())
bufpool.Put(buf)

// Render the layout 'layout' with data, using template as content key
buf = bufpool.Get()
defer bufpool.Put(buf)  
err = tmpl.ExecuteTemplate(buf, layout, data)
if err != nil {
    return err
}

布局:

<html>
<body>
   <h1>Base 1</h1>
   {{.content}}
</body>
</html>

页数:

<h2>{{.title}}</h2>
<h3>Page 1</h3>

这里是 link 完整代码:

https://play.golang.org/p/R2vr4keZec