我看不到使用动态名称调用模板(文本或HTML)的方法.示例:
这是可行的:
{{template "Blah" .}}
此错误为"意外"$BlahVar"在模板调用中":
{{$BlahVar := "Blah"}}
{{template $BlahVar .}}
我试图解决的总体问题是,我需要基于配置文件有条件地呈现模板-所以我不知道模板的名称.显然,我可以在FuncMap中放置一个函数,它只执行单独的模板解析和调用,并返回结果,但是我想知道是否有更好的方法.
我看不到使用动态名称调用模板(文本或HTML)的方法.示例:
这是可行的:
{{template "Blah" .}}
此错误为"意外"$BlahVar"在模板调用中":
{{$BlahVar := "Blah"}}
{{template $BlahVar .}}
我试图解决的总体问题是,我需要基于配置文件有条件地呈现模板-所以我不知道模板的名称.显然,我可以在FuncMap中放置一个函数,它只执行单独的模板解析和调用,并返回结果,但是我想知道是否有更好的方法.
与我一起工作的一位才华横溢的开发人员设想的另一种方法是对模板实例进行后处理,以找到任何未定义的模板,并在文件系统中查找匹配的文件并对找到的每个文件进行解析;然后呈现.
这将为您提供如下设置:
Views/index.html:
{{template "/includes/page-wrapper.html" .}}
{{define "body"}}
<div>Page guts go here</div>
{{end}}
{{define "head_section"}}
<title>Title Tag</title>
{{end}}
包括/页面包装器.html:
<html>
<head>
{{block "head_section" .}}{{end}}
<head>
<body>
{{template "body" .}}
</body>
</html>
您的ServeHTTP()
方法在"views"目录中查找文件,加载并解析它,然后调用TmplIncludeAll()
(如下所示).
我最终将这个相同的基本概念改编为几个函数,如下所示.t
是解析后呈现之前的模板.并且fs
是其中实况(如上所述)的"视图"和"包括"的目录.
func TmplIncludeAll(fs http.FileSystem, t *template.Template) error {
tlist := t.Templates()
for _, et := range tlist {
if et != nil && et.Tree != nil && et.Tree.Root != nil {
err := TmplIncludeNode(fs, et, et.Tree.Root)
if err != nil {
return err
}
}
}
return nil
}
func TmplIncludeNode(fs http.FileSystem, t *template.Template, node parse.Node) error {
if node == nil {
return nil
}
switch node := node.(type) {
case *parse.TemplateNode:
if node == nil {
return nil
}
// if template is already defined, do nothing
tlist := t.Templates()
for _, et := range tlist {
if node.Name == et.Name() {
return nil
}
}
t2 := t.New(node.Name)
f, err := fs.Open(node.Name)
if err != nil {
return err
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return err
}
_, err = t2.Parse(string(b))
if err != nil {
return err
}
// start over again, will stop recursing when there are no more templates to include
return TmplIncludeAll(fs, t)
case *parse.ListNode:
if node == nil {
return nil
}
for _, node := range node.Nodes {
err := TmplIncludeNode(fs, t, node)
if err != nil {
return err
}
}
case *parse.IfNode:
if err := TmplIncludeNode(fs, t, node.BranchNode.List); err != nil {
return err
}
if err := TmplIncludeNode(fs, t, node.BranchNode.ElseList); err != nil {
return err
}
case *parse.RangeNode:
if err := TmplIncludeNode(fs, t, node.BranchNode.List); err != nil {
return err
}
if err := TmplIncludeNode(fs, t, node.BranchNode.ElseList); err != nil {
return err
}
case *parse.WithNode:
if err := TmplIncludeNode(fs, t, node.BranchNode.List); err != nil {
return err
}
if err := TmplIncludeNode(fs, t, node.BranchNode.ElseList); err != nil {
return err
}
}
return nil
}
这是我最喜欢的方法,我已经用了一段时间了.它的优点是只有一个模板呈现,错误消息清晰明了,GO模板标记非常可读和明显.如果使用html/template.template的毅力可以简化实现,那就太好了,但总的来说,它是一个很好的解决方案.