templates - 如何使用结构或变量值的字段作为模板名称?

标签 templates go go-templates

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

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

最佳答案

很遗憾,你不能。

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

要包含的模板的名称是一个常量 字符串,它不是一个管道,它在执行期间可能会根据参数发生变化。

如果允许的语法是:

{{template pipeline}}

那么您可以使用类似 {{template .TemplName}} 的东西,但是由于语法只允许常量字符串,所以您不能。

来自 Rob 的推理为什么不允许动态模板调用(source):

We want the template language to be statically analyzable so the context of a template's invocation is clear, checkable, and lockdownable. If an invocation point is totally dynamic, this can't be done. Similarly, if a template can belong to multiple sets, its context can differ between sets in a way that would require all sets to be analyzed simultaneously. Since both these constraints are easy to work around if you want to, at the cost of losing those static checks in a higher-level package, it seemed wise to control the situation in the base template implementation. A higher-level package, such as a hypothetical HTML-only wrapper, can guarantee no workarounds more easily if the constraints are clear.

备选方案 #1:首先执行可包含模板

您可以做的是首先执行您想要包含的模板,然后将结果插入您想要包含的位置。您可以使用特殊类型在插入时不转义内部模板的结果,例如 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>.`

输出:

<html><body>
Now I will include template with name: t1
I'm template <b>t1</b>.
</body>/html>

Go Playground 上试试.

模板 t1 的结果未转义地插入。如果您省略 template.HTML:

params.Value = b.String()

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

<html><body>
Now I will include template with name: t1
I&#39;m template &lt;b&gt;t1&lt;/b&gt;.
</body>/html>

备选方案 #2:重组模板

您可以重组您的模板,避免出现您希望包含具有不同名称的模板的情况。

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

<html><body>
    Title, headers etc.
    {{template .Page}}
    Footers
</body></html>

您可以将其重组为如下所示:

header 模板:

<html><body>
    Title, headers, etc.

页脚模板:

    Footers
</body></html

您的页面模板将包括 headerfooter,如下所示:

{{template "header" .}}
    Page content comes here.
{{template "footer" .}}

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

如果您事先知道模板名称并且它不是一个详尽的列表,您可以使用 {{if}} 模板操作来包含所需的模板。示例:

{{if eq .Name "page1"}}

    {{template "page1" .}}

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

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

{{end}}

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

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

这种方式的缺点是插入内层模板的名称后,需要重新解析模板,所以不推荐这种方式。

关于templates - 如何使用结构或变量值的字段作为模板名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50933094/

相关文章:

php - vBulletin 4.0 自定义页面

c++ - 为什么下面的程序没有选择与第一个模板参数相同类型的参数?

templates - 有没有办法列出使用过的变量?

html - 从范围中获取索引号

javascript - AngularJs 创建模板指令

c++ - map 上 max_element 的模板函数需要知道这两种类型

go - 将图像附加到通过Golang Gmail API发送的电子邮件

go - 使用 go/ast 的类型断言语法

go - 将 Elm 与现有网络应用服务集成的正确方法

kubernetes-helm - 仅当映射中存在条目时才在 helm 模板中创建条目