如何加载子目录中的模板

Ari*_*Ari 2 go go-templates

我目前将所有 html 文件都放在一个平面目录中templates/,并使用以下命令加载所有内容

tmpl := template.Must(template.ParseGlob("templates/*.html"))
Run Code Online (Sandbox Code Playgroud)

但我现在想引入一些结构并将模板放入文件夹、、components等中base。但是当我这样做时,我的网站停止工作。我想可能是上面的情况,或者也可能是我需要引用模板中的路径?

例子

{{ template "navbar" }}
Run Code Online (Sandbox Code Playgroud)

会成为

{{ template "components/navbar" }}
Run Code Online (Sandbox Code Playgroud)

有点迷茫...

目前我还使用原生 go 库而不是框架。

mko*_*iva 6

Go的glob不支持匹配子目录中的文件,即**不支持。

您可以使用第三方库(github 上有许多实现),或者您可以调用filepath.Glob子目录的每个“级别”并将返回的文件名聚合到单个切片中,然后将该切片传递给template.ParseFiles

dirs := []string{
    "templates/*.html",
    "templates/*/*.html",
    "templates/*/*/*.html",
    // ...
}

files := []string{}
for _, dir := range dirs {
    ff, err := filepath.Glob(dir)
    if err != nil {
        panic(err)
    }
    files = append(files, ff...)
}

t, err := template.ParseFiles(files...)
if err != nil {
    panic(err)
}

// ...
Run Code Online (Sandbox Code Playgroud)

您还需要记住如何ParseFiles工作:(强调我的)

ParseFiles 创建一个新模板并从命名文件中解析模板定义。返回的模板的名称将具有第一个文件的(基本)名称和(已解析)内容。必须至少有一个文件。如果发生错误,解析将停止并且返回的 *Template 为零。

当解析不同目录中具有相同名称的多个文件时,最后提到的文件将是结果。例如,ParseFiles("a/foo", "b/foo") 将“b/foo”存储为名为“foo”的模板,而“a/foo”不可用。

这意味着,如果要加载所有文件,则必须确保至少以下两件事之一:(1) 每个文件的基本名称在所有模板文件中都是唯一的,而不仅仅是在文件所在的目录中,或 (2) 使用{{ define "<template_name>" }}文件内容顶部的操作为每个文件提供唯一的模板名称(并且不要忘记{{ end }}关闭define操作)。


作为第二种方法的示例,假设在您的模板中您有两个具有相同基本名称的文件,例如templates/foo/header.htmltemplates/bar/header.html,它们的内容如下:

templates/foo/header.html

<head><title>Foo Site</title></head>
Run Code Online (Sandbox Code Playgroud)

templates/bar/header.html

<head><title>Bar Site</title></head>
Run Code Online (Sandbox Code Playgroud)

现在,要给这些文件一个唯一的模板名称,您可以将内容更改为:

templates/foo/header.html

{{ define "foo/header" }}
<head><title>Foo Site</title></head>
{{ end }}
Run Code Online (Sandbox Code Playgroud)

templates/bar/header.html

{{ define "bar/header" }}
<head><title>Bar Site</title></head>
{{ end }}
Run Code Online (Sandbox Code Playgroud)

执行此操作后,您可以直接使用 执行它们t.ExecuteTemplate(w, "foo/header", nil),也可以通过让其他模板使用该{{ template "bar/header" . }}操作引用它们来间接执行它们。