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 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab
  • ¥15 求lingo代码和思路
  • ¥15 公交车和无人机协同运输