如何使用结构或变量值的字段作为模板名称?
How to use a field of struct or variable value as template name?
我们可以通过 {{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.
要包含的模板的名称是一个 常量 字符串,它不是一个 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'm template <b>t1</b>.
</body>/html>
备选方案 #2:重构模板
您可以重组您的模板,避免出现您希望包含具有不同名称的模板的情况。
示例:您可能想要创建具有 page
模板的页面,如下所示:
<html><body>
Title, headers etc.
{{template .Page}}
Footers
</body></html>
您可以将其重组为如下所示:
header
模板:
<html><body>
Title, headers, etc.
footer
模板:
Footers
</body></html
您的页面模板将包括 header
和 footer
,如下所示:
{{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:修改静态模板文本
这里的想法是,您可以手动修改外部模板的静态文本,然后插入要包含的内部模板的名称。
这种方法的缺点是插入内层模板的名称后,必须重新解析模板,所以不推荐这种方法。
我们可以通过 {{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.
要包含的模板的名称是一个 常量 字符串,它不是一个 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'm template <b>t1</b>.
</body>/html>
备选方案 #2:重构模板
您可以重组您的模板,避免出现您希望包含具有不同名称的模板的情况。
示例:您可能想要创建具有 page
模板的页面,如下所示:
<html><body>
Title, headers etc.
{{template .Page}}
Footers
</body></html>
您可以将其重组为如下所示:
header
模板:
<html><body>
Title, headers, etc.
footer
模板:
Footers
</body></html
您的页面模板将包括 header
和 footer
,如下所示:
{{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:修改静态模板文本
这里的想法是,您可以手动修改外部模板的静态文本,然后插入要包含的内部模板的名称。
这种方法的缺点是插入内层模板的名称后,必须重新解析模板,所以不推荐这种方法。