如何使用struct或variable值字段作为模板名称?

use*_*478 9 templates go go-templates

我们可以通过定义模板名称{{define "home"}},然后通过其他(父)模板加载它{{template "home"}}.

我如何通过变量值加载模板{{template .TemplateName}}.或者这不可能?

icz*_*cza 13

不幸的是你不能.

{{template}}动作的语法:

{{template "name"}}
    The template with the specified name is executed with nil data.

{{template "name" pipeline}}
    The template with the specified name is executed with dot set
    to the value of the pipeline.
Run Code Online (Sandbox Code Playgroud)

要包含的模板的名称是常量字符串,它不是基于参数在执行期间可能变化的管道.

如果允许的语法是:

{{template pipeline}}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用类似的东西,{{template .TemplName}}但由于语法只允许一个常量字符串,你不能.

从Rob推理为什么不允许动态模板调用(来源):

我们希望模板语言可以静态分析,因此模板调用的上下文是清晰,可检查和可锁定的.如果调用点完全是动态的,则无法完成.类似地,如果模板可以属于多个集合,则其上下文可以以需要同时分析所有集合的方式在集合之间不同.由于这两个约束很容易解决,如果你想以更高级别的包丢失那些静态检查为代价,控制基本模板实现中的情况似乎是明智的.如果约束条件清晰,则更高级别的包(例如假设的仅HTML包装器)可以保证无法更轻松地解决方法.

备选方案#1:首先执行Includable模板

您可以做的是执行您想要首先包含的模板,并将结果插入您想要包含它的位置.您可以使用特殊类型在插入时不要转义内部模板的结果,例如html.HTML在HTML模板的情况下.

看这个例子:

func main() {
    t := template.Must(template.New("t").Parse(t))
    template.Must(t.New("t1").Parse(t1))

    params := struct {
        Name  string
        Value interface{}
    }{"t1", nil}
    b := bytes.Buffer{}
    t.ExecuteTemplate(&b, params.Name, nil)
    params.Value = template.HTML(b.String())

    t.Execute(os.Stdout, params)
}

const t = `<html><body>
Now I will include template with name: {{.Name}}
{{.Value}}
</body>/html>`

const t1 = `I'm template <b>t1</b>.`
Run Code Online (Sandbox Code Playgroud)

输出:

<html><body>
Now I will include template with name: t1
I'm template <b>t1</b>.
</body>/html>
Run Code Online (Sandbox Code Playgroud)

Go Playground尝试一下.

模板的结果t1未插入.如果你遗漏template.HTML:

params.Value = b.String()
Run Code Online (Sandbox Code Playgroud)

t1 将被插入转义,如下所示:

<html><body>
Now I will include template with name: t1
I&#39;m template &lt;b&gt;t1&lt;/b&gt;.
</body>/html>
Run Code Online (Sandbox Code Playgroud)

备选方案#2:重组模板

您可以重新构建模板,而不是在您希望包含具有不同名称的模板的情况下.

示例:您可能希望创建具有以下page模板的页面:

<html><body>
    Title, headers etc.
    {{template .Page}}
    Footers
</body></html>
Run Code Online (Sandbox Code Playgroud)

你可以重组它是这样的:

header 模板:

<html><body>
    Title, headers, etc.
Run Code Online (Sandbox Code Playgroud)

footer 模板:

    Footers
</body></html
Run Code Online (Sandbox Code Playgroud)

而你的页面模板将包括headerfooter这样的:

{{template "header" .}}
    Page content comes here.
{{template "footer" .}}
Run Code Online (Sandbox Code Playgroud)

备选方案#3:使用{{if}}操作和预定义名称

如果您之前知道模板名称并且它不是令人筋疲力尽的列表,则可以使用{{if}}模板操作来包含所需的模板.例:

{{if eq .Name "page1"}}

    {{template "page1" .}}

{{else if eq .Name "page2"}}

    {{template "page2" .}}
    ...

{{end}}
Run Code Online (Sandbox Code Playgroud)

备选方案#4:修改静态模板文本

这里的想法是您可以手动修改外部模板的静态文本,并插入要包含的内部模板的名称.

此方法的缺点是在插入内部模板的名称后,您必须重新解析模板,因此我不建议这样做.

  • 谢谢,@ icza.真的,我现在恐慌:).我认为简单的方法存在.你的变体非常好,但在我的情况下,我更喜欢使用这样的`{{if .IsArticle}} {{template"article".} {{else}} {{template"page".}} {{end}}`.其中`IsArticle` bool标志基于用户请求(URL). (2认同)
  • @ user4611478如果您之前知道模板名称并且它不是一个令人筋疲力尽的列表,那么这也是一个非常好的选择.如果你不介意我把它包括在答案中. (2认同)