drfrvbq736383 2017-03-12 12:08
浏览 27
已采纳

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

I need to render templates into different kinds of layout. Here's my directory structure.

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

I have done rendering templates to a single layout template but, I can't make it work on multiple layouts. Here's what I got so far:

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)
}

Here's how base1.tmpl looks like:

{{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}}

And here's how page1.tmpl looks like:

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

{{define "content"}}
<p>Page 1 contents</p>
{{end}}
  • 写回答

1条回答 默认 最新

  • dongyanfeng0563 2017-03-13 20:37
    关注

    I normally take the approach of rendering twice, once for content, once for layout, this lets you use any content in any layout and defer that decision till runtime. Would be interested in other approaches if other people do it differently, but this is working for me at present.

    So using the code you have posted, something like this in handler:

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

    ...

    in renderTemplate pass in a layout as well as a template and:

    // 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
    }
    

    Layout:

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

    Page:

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

    Here is a link to full code:

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥15 python天天向上类似问题,但没有清零
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 C#调用python代码(python带有库)
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?