Golang中HTML/template布局与内容文件的使用指南

Golang中HTML/template布局与内容文件的使用指南 我编写了一个处理程序来解析布局文件和内容文件

func homeHandler(w http.ResponseWriter, r *http.Request) {
	tmpl, err := template.ParseFiles("ui/templates/layouts/layout.html", "ui/templates/index.html")
	if err != nil {
		panic(err)
	}
	tmpl.ExecuteTemplate(w, "layout.html", nil)
}

我的 layout.html 如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    {{template "content" .}}
</body>
</html>

index.html 文件如下所示:

{{define "content"}}
<h1>This is the index Page</h1>
{{end}}

我的问题是:每次调用处理程序时都解析文件是一种好的做法吗,是否有其他方法来实现布局和内容样式?


更多关于Golang中HTML/template布局与内容文件的使用指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复
你是说 `hugo` 会为每个请求都解析文件吗?

更多关于Golang中HTML/template布局与内容文件的使用指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Hugo 一次性解析并构建静态内容。

我指的是它们在解析器、结构等方面的工作方式。

编辑:

一个很好的例子是他们的主题模块系统,成功地在多个方面分离了模板,并通过"shortcodes"插件简化了上层渲染代码。

另一个很好的例子是分离解析(本地和主题仓库)。这样,设计师只需处理 HTML 部分,而您的 Go 代码保持不变。

如果您正在创建一个完全兼容的解析器,您可以重用所有可用的 Hugo 主题,从而在设计代码上节省大量时间。

AlwinDoss: 每次调用处理程序时都解析文件是好的做法吗?有没有其他方法来实现布局和内容样式?

这取决于您的部署资源。如果内存资源充足且静态文件(如HTML等)不经常更改,您可以在首次解析时将其缓存到内存中。

或者,您可以使用像packr这样的库将其嵌入到Go二进制文件中,并将其功能化以实现最佳内存管理。缺点是根据以往经验,二进制文件通常非常大(>100MB)。好处是在这种模式下您实现了无依赖。

否则,解析也是可以的。如果您需要参考,Hugo是一个很好的例子。

在Go中每次请求都解析模板文件确实不是最佳实践,这会导致不必要的性能开销。更好的做法是在程序启动时解析模板并缓存它们。

以下是改进后的实现:

var templates = template.Must(template.ParseGlob("ui/templates/*.html"))

func homeHandler(w http.ResponseWriter, r *http.Request) {
    err := templates.ExecuteTemplate(w, "layout.html", nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

或者使用更结构化的方式:

type TemplateCache struct {
    templates *template.Template
}

var tc *TemplateCache

func init() {
    tc = &TemplateCache{
        templates: template.Must(template.ParseGlob("ui/templates/*.html")),
    }
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    err := tc.templates.ExecuteTemplate(w, "layout.html", nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

对于更复杂的布局管理,可以使用ParseFiles组合多个文件:

var templates = template.Must(template.New("").ParseFiles(
    "ui/templates/layouts/layout.html",
    "ui/templates/index.html",
    "ui/templates/about.html",
))

func homeHandler(w http.ResponseWriter, r *http.Request) {
    err := templates.ExecuteTemplate(w, "layout.html", nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

使用template.Must可以在解析失败时直接panic,这在程序启动时是合适的。缓存模板后,每次请求只需执行模板,大大提高了性能。

你的模板结构是正确的,layout.html通过{{template "content" .}}来嵌入内容模板,而index.html通过{{define "content"}}定义了具体的内容块。

回到顶部