Sim, é possível. A html.Template
é na verdade um conjunto de arquivos de modelo. Se você executar um bloco definido neste conjunto, ele terá acesso a todos os outros blocos definidos neste conjunto.
Se você criar um mapa desses conjuntos de modelos por conta própria, terá basicamente a mesma flexibilidade que o Jinja / Django oferece. A única diferença é que o pacote html / template não tem acesso direto ao sistema de arquivos, então você precisa analisar e compor os modelos por conta própria.
Considere o seguinte exemplo com duas páginas diferentes ("index.html" e "other.html") que herdam de "base.html":
{{define "base"}}<html>
<head>{{template "head" .}}</head>
<body>{{template "body" .}}</body>
</html>{{end}}
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}
E o seguinte mapa de conjuntos de modelos:
tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))
Agora você pode renderizar sua página "index.html" chamando
tmpl["index.html"].Execute("base", data)
e você pode renderizar sua página "other.html" chamando
tmpl["other.html"].Execute("base", data)
Com alguns truques (por exemplo, uma convenção de nomenclatura consistente para seus arquivos de modelo), é até possível gerar o tmpl
mapa automaticamente.
tmpl["index.html"].ExecuteTemplate(w, "base", data)
.{{ .SomeData }}
não serão exibidos no modelo interno. O exterior funciona.template.ParseFiles("index.html", "base.html")
étemplate.ParseFiles("base.html", "index.html")
?note, quando você executa seu template base, você deve passar os valores para os templates filhos, aqui eu simplesmente passo ".", para que tudo seja passado.
o modelo um exibe {{.}}
{{define "base"}} <html> <div class="container"> {{.}} {{template "content" .}} </div> </body> </html> {{end}}
o modelo dois exibe {{.domains}} que é passado para o pai.
{{define "content"}} {{.domains}} {{end}}
Observe, se usássemos {{template "content".}} Em vez de {{template "content".}}, .Domains não seria acessível a partir do template de conteúdo.
DomainsData := make(map[string]interface{}) DomainsData["domains"] = domains.Domains if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) }
fonte
tendo trabalhado com outros pacotes de modelo, hoje em dia eu trabalho principalmente com o pacote html / template padrão, acho que fui ingênuo por não apreciar a simplicidade que ele oferece e outras vantagens. Eu uso uma abordagem muito semelhante para resposta aceita com as seguintes alterações
você não precisa embrulhar seus layouts com um
base
modelo adicional , um bloco de modelo é criado para cada arquivo analisado, então, neste caso, é redundante, eu também gosto de usar a ação de bloqueio fornecida na nova versão do go, que permite que você tenha conteúdo de bloco padrão no caso de você não fornecer um em modelos filhos// base.html <head>{{block "head" .}} Default Title {{end}}</head> <body>{{block "body" .}} default body {{end}}</body>
e seus modelos de página podem ser os mesmos
// Content of index.html: {{define "head"}}<title>index</title>{{end}} {{define "body"}}index{{end}} // Content of other.html: {{define "head"}}<title>other</title>{{end}} {{define "body"}}other{{end}}
agora para executar os modelos você precisa chamá-lo assim
tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)
fonte
Use Pongo , que é um superconjunto de modelos Go que suporta as tags {{extends}} e {{block}} para herança de template, assim como o Django.
fonte
Eu tenho voltado a esta resposta há dias, finalmente mordi a bala e escrevi uma pequena camada de abstração / pré-processador para isso. Basicamente:
https://github.com/daemonl/go_sweetpl
fonte