英文:
HTML Partials in GoLang
问题
我刚刚开始学习Go语言,并且想用它创建一个Web应用程序。我现在正在尝试以类似于handlebarsjs的方式使用模板。我想将页眉和页脚从主页面中分离出来,以便在每个网页中注入它们。
我的当前设置应该解析主页、页眉和页脚的HTML文件并将它们缓存起来。然后我执行我的home.html模板,该模板包含页面标题、header.html文件和footer.html文件的字段。
每当我搜索类似的页面时,我只看到JavaScript页面,所以如果这是一个重复的问题,请告诉我应该去哪里找。
编辑:
我已经根据@Minty和@putu的答案更新了我的代码。我正在尝试读取HTML文件并将它们存储在数据映射中,同时还向我的模板添加了define
。目前有一些新的错误需要解决,所以网站目前无法渲染。但是,如果你有任何新的建议,那将非常有帮助。
server.go
package main
import (
"html/template"
"io/ioutil"
"net/http"
"regexp"
)
var tPath = "./temps/"
var dPath = "./data/"
var templates = template.Must(template.ParseFiles(tPath+"home.html", dPath+"header.html", dPath+"footer.html"))
var validPath = regexp.MustCompile("^/")
func rootHandler(wr http.ResponseWriter, req *http.Request) {
title := "home"
headerFile, headErr := ioutil.ReadFile(dPath + "header.html")
footerFile, footErr := ioutil.ReadFile(dPath + "footer.html")
if headErr != nil || footErr != nil {
http.Error(wr, headErr.Error(), http.StatusInternalServerError)
http.Error(wr, footErr.Error(), http.StatusInternalServerError)
}
data := map[string]interface{}{
"Title": title,
"Header": string(headerFile),
"Footer": string(footerFile),
}
err := templates.ExecuteTemplate(wr, title+".html", data)
if err != nil {
http.Error(wr, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8080", nil)
}
home.html:
{{define "homeHTML"}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{.Title}} - MySite</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
{{.Header}}
<h1>Welcome!</h1>
{{.Footer}}
</body>
</html>
{{end}}
Header.html:
{{define "headerHTML"}}
<header>
<h1>MySite</h1>
<br>
<nav>
<a href="/">Home</a>
</nav>
</header>
{{end}}
Footer.html
{{define "footerHTML"}}
<footer>
<p>Thank You for Visiting</p>
</footer>
{{end}}
英文:
I am just getting started with Go, and I want to create a web app with it. What I am trying now is to use the templating in a handlebarsjs-esque manner. I want to pull my header and footer out of my main page so I can inject them on every webpage.
My current set up is supposed to parse the homepage, header, and footer HTML files and cache them. Then I execute my home.html template, which has fields for the pages Title, the header.html file, and the footer.html file.
Whenever I search for similar pages I just see javascript pages, so if this is a repost, let me know where to look.
edit:
I have updated my code to take tips from the answers by @Minty and @putu. I am trying to read the html files and store them in a data map, while also adding the template define
to my templates. There are some new bugs that I am working on squashing, so the site does not render currently. But, if there are any new tips you can give, that would help a lot.
server.go
package main
import (
"html/template"
"io/ioutil"
"net/http"
"regexp"
)
var tPath = "./temps/"
var dPath = "./data/"
var templates = template.Must(template.ParseFiles(tPath+"home.html", dPath+"header.html", dPath+"footer.html"))
var validPath = regexp.MustCompile("^/")
func rootHandler(wr http.ResponseWriter, req *http.Request) {
title := "home"
headerFile, headErr := ioutil.ReadFile(dPath + "header.html")
footerFile, footErr := ioutil.ReadFile(dPath + "footer.html")
if headErr != nil || footErr != nil {
http.Error(wr, headErr.Error(), http.StatusInternalServerError)
http.Error(wr, footErr.Error(), http.StatusInternalServerError)
}
data := map[string]interface{}{
"Title": title,
"Header": string(headerFile),
"Footer": string(footerFile),
}
err := templates.ExecuteTemplate(wr, title+".html", data)
if err != nil {
http.Error(wr, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8080", nil)
}
home.html:
{{define "homeHTML"}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{.Title}} - MySite</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
{{.Header}}
<h1>Welcome!</h1>
{{.Footer}}
</body>
</html>
{{end}}
Header.html:
{{define "headerHTML"}}
<header>
<h1>MySite</h1>
<br>
<nav>
<a href="/">Home</a>
</nav>
</header>
{{end}}
Footer.html
{{define "footerHTML"}}
<footer>
<p>Thank You for Visiting</p>
</footer>
{{end}}
答案1
得分: 13
这是一个完整的工作示例。
在temps文件夹中的home.html:
{{define "homeHTML"}}
{{template "headHTML" .}}
{{template "headerHTML" .}}
{{template "footerHTML" .}}
{{end}}
在data文件夹中的head.html:
{{define "headHTML"}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{.title}} - MySite</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
{{end}}
在data文件夹中的header.html:
{{define "headerHTML"}}
<header>
{{.header}}
<h1>Welcome to my site!</h1>
<br>
<nav>
<a href="/">Home</a>
</nav>
</header>
{{end}}
在data文件夹中的footer.html:
{{define "footerHTML"}}
<h1>Welcome! {{.footer}}</h1>
<footer>
<p>Thank You for Visiting</p>
</footer>
</body>
</html>
{{end}}
代码如下:
package main
import (
"html/template"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
)
var tPath = "./temps/"
var dPath = "./data/"
var templateDirs = []string{"temps", "data"}
var templates *template.Template
func getTemplates() (templates *template.Template, err error) {
var allFiles []string
for _, dir := range templateDirs {
files2, _ := ioutil.ReadDir(dir)
for _, file := range files2 {
filename := file.Name()
if strings.HasSuffix(filename, ".html") {
filePath := filepath.Join(dir, filename)
allFiles = append(allFiles, filePath)
}
}
}
templates, err = template.New("").ParseFiles(allFiles...)
return
}
func init() {
templates, _ = getTemplates()
}
func rootHandler(wr http.ResponseWriter, req *http.Request) {
title := "home"
data := map[string]interface{}{
"title": title,
"header": "My Header",
"footer": "My Footer",
}
err := templates.ExecuteTemplate(wr, "homeHTML", data)
if err != nil {
http.Error(wr, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8080", nil)
}
以上是翻译好的内容。
英文:
This is full working example.
home.html inside temps folder:
{{define "homeHTML"}}
{{template "headHTML" .}}
{{template "headerHTML" .}}
{{template "footerHTML" .}}
{{end}}
head.html inside data folder:
{{define "headHTML"}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{.title}} - MySite</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
{{end}}
header.html inside data folder
{{define "headerHTML"}}
<header>
{{.header}}
<h1>Welcome to my site!</h1>
<br>
<nav>
<a href="/">Home</a>
</nav>
</header>
{{end}}
footer.html inside data folder:
{{define "footerHTML"}}
<h1>Welcome! {{.footer}}</h1>
<footer>
<p>Thank You for Visiting</p>
</footer>
</body>
</html>
{{end}}
And the code will be like this
package main
import (
"html/template"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
)
var tPath = "./temps/"
var dPath = "./data/"
var templateDirs = []string{"temps", "data"}
var templates *template.Template
func getTemplates() (templates *template.Template, err error) {
var allFiles []string
for _, dir := range templateDirs {
files2, _ := ioutil.ReadDir(dir)
for _, file := range files2 {
filename := file.Name()
if strings.HasSuffix(filename, ".html") {
filePath := filepath.Join(dir, filename)
allFiles = append(allFiles, filePath)
}
}
}
templates, err = template.New("").ParseFiles(allFiles...)
return
}
func init() {
templates, _ = getTemplates()
}
func rootHandler(wr http.ResponseWriter, req *http.Request) {
title := "home"
data := map[string]interface{}{
"title": title,
"header": "My Header",
"footer": "My Footer",
}
err := templates.ExecuteTemplate(wr, "homeHTML", data)
if err != nil {
http.Error(wr, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8080", nil)
}
答案2
得分: 1
你需要将数据作为struct
或map
传递给模板。以下是使用map
的rootHandler
示例:
func rootHandler(wr http.ResponseWriter, req *http.Request) {
title := "home"
//将变量包装到map中
data := map[string]interface{}{
"Title": title,
"IntVar": 100,
}
err := templates.ExecuteTemplate(wr, title+".html", data)
//其他代码...
}
有关更多详细信息,请参阅文档。
英文:
You need to pass the data as struct
or map
to template. Example of your rootHandler
using map
:
func rootHandler(wr http.ResponseWriter, req *http.Request) {
title := "home"
//Wrap your variable into a map
data := map[string]interface{}{
"Title": title,
"IntVar": 100,
}
err := templates.ExecuteTemplate(wr, title+".html", data)
//other codes...
}
For more details, see documentation.
答案3
得分: 1
接受的答案可以通过使用template.ParseGlob来简化。
将func getTemplates()的内容替换为:
templates, err := template.ParseGlob("temps/*")
if err != nil {
return nil, err
}
return templates.ParseGlob("data/*")
英文:
The accepted answer can be simplified by using template.ParseGlob
Replace the contents of func getTemplates() with
templates, err:= template.ParseGlob("temps/*")
if err!= nil {
return nil, err
}
return templates.ParseGlob("data/*)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论