如何加载子目录中的模板

How to load templates in subdirectories

我目前所有的 html 文件都在一个平面目录 templates/ 中,我用

加载所有内容
tmpl := template.Must(template.ParseGlob("templates/*.html"))

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

例子

{{ template "navbar" }}

会变成

{{ template "components/navbar" }}

有点迷糊...

我现在也在使用原生的 go 库,而不是框架。

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

您可以使用第三方库(github 上有许多实现),或者您可以为每个 "level" 子目录和聚合调用 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)
}

// ...

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

ParseFiles creates a new Template and parses the template definitions from the named files. The returned template's name will have the (base) name and (parsed) contents of the first file. There must be at least one file. If an error occurs, parsing stops and the returned *Template is nil.

When parsing multiple files with the same name in different directories, the last one mentioned will be the one that results. For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template named "foo", while "a/foo" is unavailable.

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


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

templates/foo/header.html

<head><title>Foo Site</title></head>

templates/bar/header.html

<head><title>Bar Site</title></head>

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

templates/foo/header.html

{{ define "foo/header" }}
<head><title>Foo Site</title></head>
{{ end }}

templates/bar/header.html

{{ define "bar/header" }}
<head><title>Bar Site</title></head>
{{ end }}

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