Go 模板和嵌入:使用模板块时一个模板的内容覆盖另一个模板

问题描述 投票:0回答:1

我一直在尝试理解 html/template 包与 golang 1.23 中的 embed 包的结合,但我什至很难获得一个可以运行两个页面的简单基本布局。如下详述,我遇到了一些内容覆盖(至少我怀疑这是问题),其中为不同的路线显示一个相同的 html 渲染。

我的最小示例的文件结构如下:

- templates/
    - layout.html
    - page1.html
    - page2.html

- main.go
- go.mod

服务器嵌入 html 文件并使用标准 net/http 包(1.23)为其提供服务:

main.go

package main

import (
    "embed"
    "html/template"
    "log"
    "net/http"
)

//go:embed templates/*.html
var templateFS embed.FS

var templates *template.Template

func main() {
    var err error

    templates, err = template.ParseFS(templateFS, "templates/*.html")
    if err != nil {
        log.Fatal("Error parsing templates: ", err)
    }

    http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
        http.Redirect(w, r, "/page1", http.StatusSeeOther)
    })

    http.HandleFunc("GET /page1", func(w http.ResponseWriter, r *http.Request) {
        err := templates.ExecuteTemplate(w, "page1", nil)
        if err != nil {
            http.Error(w, "Template rendering error: "+err.Error(), http.StatusInternalServerError)
        }
    })

    http.HandleFunc("GET /page2", func(w http.ResponseWriter, r *http.Request) {
        err := templates.ExecuteTemplate(w, "page2", nil)
        if err != nil {
            http.Error(w, "Template rendering error: "+err.Error(), http.StatusInternalServerError)
        }
    })

    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

现在我尝试设计模板的方式是典型的基本布局,它通过子页面“填充”。

layout.html

{{ define "layout" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>{{ block "title" . }}My Website{{ end }}</title>
</head>
<body>
    <header>
        <h1>Welcome!</h1>
        <nav>
            <a href="/page1">Page 1</a> | 
            <a href="/page2">Page 2</a>
        </nav>
    </header>
    <main>
        {{ block "content" . }}{{ end }}
    </main>
</body>
</html>
{{ end }}

还有两个简单的子页面:

page1.html

{{ define "page1"}}
{{ template "layout" . }}
{{ end }}

{{ block "title" . }}Page 1{{ end }}

{{ block "content" . }}
    <h2>This is Page 1</h2>
    <p>Content for page 1 goes here.</p>
{{ end }}

page2.html

{{ define "page2"}}
{{ template "layout" . }}
{{ end }}

{{ block "title" . }}Page 2{{ end }}

{{ block "content" . }}
    <h2>This is Page 2</h2>
    <p>Content for page 2 goes here.</p>
{{ end }}

现在发生的情况是,对于

http://localhost:8080/page1
http://localhost:8080/page2
,即使我在两个路由的
ExecuteTemplate
函数调用中切换名称字符串,也会显示第 2 页的模板。

我已经对第 1/2 页的模板进行了很多实验(将块声明移入和移出定义,使用模板操作而不是块操作等)。我怀疑当涉及到 golang 的模板包或嵌入包引入的一些副作用时,我缺少一些非常重要的基础知识。你们能给我一点提示吗?

(我很乐意使用标准包来完成此操作,而不是 templp 等)

html go templates package
1个回答
0
投票

解析模板时,模板的顺序很重要。试试这个:

  1. 参考其他模板定义布局:
<!DOCTYPE HTML>
...
{{template "title" .}}
...
{{template "content" .}}}
...

{{define "title"}}{{end}}
{{define "content"}}{{end}}
  1. 定义各个页面
page1: 
{{define "title"}}Title1 contents{{end}}
{{define "content"}}Page 1 Contents{{end}}

page2:
{{define "title"}}Title2 contents{{end}}
{{define "content"}}Page 2 Contents{{end}}
  1. 解析两个模板,一个用于 page1,一个用于 page2。 Page1 应包括布局和 page1。第 2 页应包含布局和第 2 页。
page1Templ := template.Must(template.New("p1").Parse(layout))
template.Must(page1Templ.Parse(page1))
page2Templ := template.Must(template.New("p2").Parse(layout))
template.Must(page2Templ.Parse(page2))
  1. 对第 1 页执行 page1Templ,对第 2 页执行 page2Templ。

这样每个模板都将包含布局和相应的页面定义。

© www.soinside.com 2019 - 2024. All rights reserved.