Golang中如何构建头部和基础模板

Golang中如何构建头部和基础模板 我正在开始学习Go语言,在寻找成熟的Web框架之前,先看了一下Web开发(内置功能)。我看到了关于模板的内容:

<h1>{{.PageTitle}}</h1>
<ul>
    {{range .Todos}}
        {{if .Done}}
            <li class="done">{{.Title}}</li>
        {{else}}
            <li>{{.Title}}</li>
        {{end}}
    {{end}}
</ul>

这是由下面的Go代码加载的:

package main


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



type Todo struct {
    Title string
    Done  bool
}



type TodoPageData struct {
    PageTitle string
    Todos     []Todo
}



func main() {
    tmpl := template.Must(template.ParseFiles("layout.html"))
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := TodoPageData{
            PageTitle: "My TODO list",
            Todos: []Todo{
                {Title: "Task 1", Done: false},
                {Title: "Task 2", Done: true},
                {Title: "Task 3", Done: true},
            },
        }
        tmpl.Execute(w, data)
    })
    http.ListenAndServe(":80", nil)
}

我的问题是: 如何同时加载两个模板,比如一个base模板和一个index模板,这样无论加载的是索引页还是其他页面,基础模板都保持不变。

类似于PHP中的[header](https://www.php.net/manual/en/function.header.php)

<html>
<?php
/* This will give an error. Note the output
 * above, which is before the header() call */
header('Location: http://www.example.com/');
exit;
?>

或者Django中的[extending](https://tutorial.djangogirls.org/en/template_extending/)

{% extends 'blog/base.html' %}

{% block content %}
    {% for post in posts %}
        <div class="post">
            <div class="date">
                {{ post.published_date }}
            </div>
            <h2><a href="">{{ post.title }}</a></h2>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}

更多关于Golang中如何构建头部和基础模板的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

通过两次使用上述代码,一次用于 layout/header,紧接着一次用于 index,它对我起作用了,所以我的代码变成了:

	tmpl_layout := template.Must(template.ParseFiles("layout.html"))
	tmpl_index := template.Must(template.ParseFiles("index.html"))
		if r.Method != http.MethodPost {
			tmpl_layout.Execute(w, nil)
			tmpl_index.Execute(w, nil)
			return
		}

		tmpl_layout.Execute(w, nil)
		tmpl_index.Execute(w, struct{ Success bool }{true})

html 文件很简单,没有额外内容,像这样:

// 文件: layout.html
 <h1>Welcome</h1>

// 文件: index.html
 <h1>Nice to see you here</h1>

我尝试按照这个方法做,但对我没用。我不确定对我起作用的代码是否正确,以及书中的代码是否过时了,或者问题可能是什么!

更多关于Golang中如何构建头部和基础模板的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,可以通过模板组合和继承来实现头部和基础模板。以下是几种常见的方法:

方法1:使用template.ParseFiles加载多个模板

package main

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

func main() {
    // 加载多个模板文件
    tmpl := template.Must(template.ParseFiles("base.html", "index.html"))
    
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := map[string]interface{}{
            "Title": "首页",
            "Content": "这是首页内容",
        }
        // 执行特定的模板
        tmpl.ExecuteTemplate(w, "index.html", data)
    })
    
    http.ListenAndServe(":8080", nil)
}

方法2:使用模板继承(类似Django)

base.html(基础模板):

<!DOCTYPE html>
<html>
<head>
    <title>{{block "title" .}}默认标题{{end}}</title>
    <style>
        body { font-family: Arial, sans-serif; }
        .header { background: #333; color: white; padding: 10px; }
        .content { padding: 20px; }
    </style>
</head>
<body>
    <div class="header">
        <h1>{{block "header" .}}网站标题{{end}}</h1>
    </div>
    
    <div class="content">
        {{block "content" .}}默认内容{{end}}
    </div>
    
    <div class="footer">
        {{block "footer" .}}© 2023 我的网站{{end}}
    </div>
</body>
</html>

index.html(继承基础模板):

{{define "title"}}首页 - 我的网站{{end}}

{{define "header"}}欢迎来到首页{{end}}

{{define "content"}}
    <h2>最新文章</h2>
    <ul>
        {{range .Articles}}
        <li>{{.Title}} - {{.Date}}</li>
        {{end}}
    </ul>
{{end}}

{{define "footer"}}
    <p>© 2023 我的网站 | 联系: contact@example.com</p>
{{end}}

Go代码

package main

import (
    "html/template"
    "net/http"
    "time"
)

type Article struct {
    Title string
    Date  time.Time
}

func main() {
    // 加载所有模板
    tmpl := template.Must(template.ParseFiles("base.html", "index.html", "about.html"))
    
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := map[string]interface{}{
            "Articles": []Article{
                {Title: "Go语言入门", Date: time.Now().AddDate(0, 0, -2)},
                {Title: "模板使用指南", Date: time.Now().AddDate(0, 0, -1)},
                {Title: "Web开发实践", Date: time.Now()},
            },
        }
        // 执行基础模板,它会自动包含index.html中定义的块
        tmpl.ExecuteTemplate(w, "base.html", data)
    })
    
    http.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {
        data := map[string]interface{}{
            "Title": "关于我们",
        }
        tmpl.ExecuteTemplate(w, "base.html", data)
    })
    
    http.ListenAndServe(":8080", nil)
}

方法3:使用模板包含(Include)

header.html

<header>
    <nav>
        <a href="/">首页</a>
        <a href="/about">关于</a>
        <a href="/contact">联系</a>
    </nav>
    <h1>{{.SiteTitle}}</h1>
</header>

footer.html

<footer>
    <p>版权所有 &copy; {{.Year}} {{.CompanyName}}</p>
</footer>

layout.html

<!DOCTYPE html>
<html>
<head>
    <title>{{.PageTitle}}</title>
</head>
<body>
    {{template "header.html" .}}
    
    <main>
        {{template "content" .}}
    </main>
    
    {{template "footer.html" .}}
</body>
</html>

index.html

{{define "content"}}
    <h2>欢迎</h2>
    <p>{{.WelcomeMessage}}</p>
    <ul>
        {{range .Items}}
        <li>{{.}}</li>
        {{end}}
    </ul>
{{end}}

Go代码

package main

import (
    "html/template"
    "net/http"
    "time"
)

func main() {
    // 使用ParseGlob加载所有模板文件
    tmpl := template.Must(template.ParseGlob("templates/*.html"))
    
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := map[string]interface{}{
            "PageTitle":      "首页",
            "SiteTitle":      "我的Go网站",
            "CompanyName":    "Go科技有限公司",
            "Year":           time.Now().Year(),
            "WelcomeMessage": "欢迎访问我们的网站",
            "Items":          []string{"产品1", "产品2", "产品3"},
        }
        
        tmpl.ExecuteTemplate(w, "layout.html", data)
    })
    
    http.ListenAndServe(":8080", nil)
}

方法4:使用模板函数处理通用部分

package main

import (
    "html/template"
    "net/http"
    "strings"
)

func main() {
    // 创建模板函数映射
    funcMap := template.FuncMap{
        "toUpper": strings.ToUpper,
        "formatTitle": func(title string) string {
            return "MySite - " + title
        },
    }
    
    // 解析模板并添加函数
    tmpl := template.Must(template.New("").Funcs(funcMap).ParseFiles(
        "base.tmpl",
        "index.tmpl",
        "partials/header.tmpl",
        "partials/footer.tmpl",
    ))
    
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := struct {
            Title   string
            Content string
            User    string
        }{
            Title:   "首页",
            Content: "欢迎内容",
            User:    "访客",
        }
        
        // 使用模板布局
        err := tmpl.ExecuteTemplate(w, "base.tmpl", data)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    })
    
    http.ListenAndServe(":8080", nil)
}

这些方法展示了Go语言中如何实现模板的复用和继承。template.ParseFiles可以加载多个模板文件,ExecuteTemplate可以指定执行哪个模板,而模板中的{{define}}{{block}}指令提供了模板继承和覆盖的机制。

回到顶部