HTML Partials in GoLang

huangapple go评论145阅读模式
英文:

HTML Partials in GoLang

问题

我刚刚开始学习Go语言,并且想用它创建一个Web应用程序。我现在正在尝试以类似于handlebarsjs的方式使用模板。我想将页眉和页脚从主页面中分离出来,以便在每个网页中注入它们。

我的当前设置应该解析主页、页眉和页脚的HTML文件并将它们缓存起来。然后我执行我的home.html模板,该模板包含页面标题、header.html文件和footer.html文件的字段。

每当我搜索类似的页面时,我只看到JavaScript页面,所以如果这是一个重复的问题,请告诉我应该去哪里找。

编辑:
我已经根据@Minty和@putu的答案更新了我的代码。我正在尝试读取HTML文件并将它们存储在数据映射中,同时还向我的模板添加了define。目前有一些新的错误需要解决,所以网站目前无法渲染。但是,如果你有任何新的建议,那将非常有帮助。

server.go

  1. package main
  2. import (
  3. "html/template"
  4. "io/ioutil"
  5. "net/http"
  6. "regexp"
  7. )
  8. var tPath = "./temps/"
  9. var dPath = "./data/"
  10. var templates = template.Must(template.ParseFiles(tPath+"home.html", dPath+"header.html", dPath+"footer.html"))
  11. var validPath = regexp.MustCompile("^/")
  12. func rootHandler(wr http.ResponseWriter, req *http.Request) {
  13. title := "home"
  14. headerFile, headErr := ioutil.ReadFile(dPath + "header.html")
  15. footerFile, footErr := ioutil.ReadFile(dPath + "footer.html")
  16. if headErr != nil || footErr != nil {
  17. http.Error(wr, headErr.Error(), http.StatusInternalServerError)
  18. http.Error(wr, footErr.Error(), http.StatusInternalServerError)
  19. }
  20. data := map[string]interface{}{
  21. "Title": title,
  22. "Header": string(headerFile),
  23. "Footer": string(footerFile),
  24. }
  25. err := templates.ExecuteTemplate(wr, title+".html", data)
  26. if err != nil {
  27. http.Error(wr, err.Error(), http.StatusInternalServerError)
  28. }
  29. }
  30. func main() {
  31. http.HandleFunc("/", rootHandler)
  32. http.ListenAndServe(":8080", nil)
  33. }

home.html:

  1. {{define "homeHTML"}}
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="utf-8">
  6. <title>{{.Title}} - MySite</title>
  7. <link rel="stylesheet" type="text/css" href="style.css">
  8. </head>
  9. <body>
  10. {{.Header}}
  11. <h1>Welcome!</h1>
  12. {{.Footer}}
  13. </body>
  14. </html>
  15. {{end}}

Header.html:

  1. {{define "headerHTML"}}
  2. <header>
  3. <h1>MySite</h1>
  4. <br>
  5. <nav>
  6. <a href="/">Home</a>
  7. </nav>
  8. </header>
  9. {{end}}

Footer.html

  1. {{define "footerHTML"}}
  2. <footer>
  3. <p>Thank You for Visiting</p>
  4. </footer>
  5. {{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

  1. package main
  2. import (
  3. "html/template"
  4. "io/ioutil"
  5. "net/http"
  6. "regexp"
  7. )
  8. var tPath = "./temps/"
  9. var dPath = "./data/"
  10. var templates = template.Must(template.ParseFiles(tPath+"home.html", dPath+"header.html", dPath+"footer.html"))
  11. var validPath = regexp.MustCompile("^/")
  12. func rootHandler(wr http.ResponseWriter, req *http.Request) {
  13. title := "home"
  14. headerFile, headErr := ioutil.ReadFile(dPath + "header.html")
  15. footerFile, footErr := ioutil.ReadFile(dPath + "footer.html")
  16. if headErr != nil || footErr != nil {
  17. http.Error(wr, headErr.Error(), http.StatusInternalServerError)
  18. http.Error(wr, footErr.Error(), http.StatusInternalServerError)
  19. }
  20. data := map[string]interface{}{
  21. "Title": title,
  22. "Header": string(headerFile),
  23. "Footer": string(footerFile),
  24. }
  25. err := templates.ExecuteTemplate(wr, title+".html", data)
  26. if err != nil {
  27. http.Error(wr, err.Error(), http.StatusInternalServerError)
  28. }
  29. }
  30. func main() {
  31. http.HandleFunc("/", rootHandler)
  32. http.ListenAndServe(":8080", nil)
  33. }

home.html:

  1. {{define "homeHTML"}}
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="utf-8">
  6. <title>{{.Title}} - MySite</title>
  7. <link rel="stylesheet" type="text/css" href="style.css">
  8. </head>
  9. <body>
  10. {{.Header}}
  11. <h1>Welcome!</h1>
  12. {{.Footer}}
  13. </body>
  14. </html>
  15. {{end}}

Header.html:

  1. {{define "headerHTML"}}
  2. <header>
  3. <h1>MySite</h1>
  4. <br>
  5. <nav>
  6. <a href="/">Home</a>
  7. </nav>
  8. </header>
  9. {{end}}

Footer.html

  1. {{define "footerHTML"}}
  2. <footer>
  3. <p>Thank You for Visiting</p>
  4. </footer>
  5. {{end}}

答案1

得分: 13

这是一个完整的工作示例。

在temps文件夹中的home.html:

  1. {{define "homeHTML"}}
  2. {{template "headHTML" .}}
  3. {{template "headerHTML" .}}
  4. {{template "footerHTML" .}}
  5. {{end}}

在data文件夹中的head.html:

  1. {{define "headHTML"}}
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="utf-8">
  6. <title>{{.title}} - MySite</title>
  7. <link rel="stylesheet" type="text/css" href="style.css">
  8. </head>
  9. {{end}}

在data文件夹中的header.html:

  1. {{define "headerHTML"}}
  2. <header>
  3. {{.header}}
  4. <h1>Welcome to my site!</h1>
  5. <br>
  6. <nav>
  7. <a href="/">Home</a>
  8. </nav>
  9. </header>
  10. {{end}}

在data文件夹中的footer.html:

  1. {{define "footerHTML"}}
  2. <h1>Welcome! {{.footer}}</h1>
  3. <footer>
  4. <p>Thank You for Visiting</p>
  5. </footer>
  6. </body>
  7. </html>
  8. {{end}}

代码如下:

  1. package main
  2. import (
  3. "html/template"
  4. "io/ioutil"
  5. "net/http"
  6. "path/filepath"
  7. "strings"
  8. )
  9. var tPath = "./temps/"
  10. var dPath = "./data/"
  11. var templateDirs = []string{"temps", "data"}
  12. var templates *template.Template
  13. func getTemplates() (templates *template.Template, err error) {
  14. var allFiles []string
  15. for _, dir := range templateDirs {
  16. files2, _ := ioutil.ReadDir(dir)
  17. for _, file := range files2 {
  18. filename := file.Name()
  19. if strings.HasSuffix(filename, ".html") {
  20. filePath := filepath.Join(dir, filename)
  21. allFiles = append(allFiles, filePath)
  22. }
  23. }
  24. }
  25. templates, err = template.New("").ParseFiles(allFiles...)
  26. return
  27. }
  28. func init() {
  29. templates, _ = getTemplates()
  30. }
  31. func rootHandler(wr http.ResponseWriter, req *http.Request) {
  32. title := "home"
  33. data := map[string]interface{}{
  34. "title": title,
  35. "header": "My Header",
  36. "footer": "My Footer",
  37. }
  38. err := templates.ExecuteTemplate(wr, "homeHTML", data)
  39. if err != nil {
  40. http.Error(wr, err.Error(), http.StatusInternalServerError)
  41. }
  42. }
  43. func main() {
  44. http.HandleFunc("/", rootHandler)
  45. http.ListenAndServe(":8080", nil)
  46. }

以上是翻译好的内容。

英文:

This is full working example.

home.html inside temps folder:

  1. {{define &quot;homeHTML&quot;}}
  2. {{template &quot;headHTML&quot; .}}
  3. {{template &quot;headerHTML&quot; .}}
  4. {{template &quot;footerHTML&quot; .}}
  5. {{end}}

head.html inside data folder:

  1. {{define &quot;headHTML&quot;}}
  2. &lt;!DOCTYPE html&gt;
  3. &lt;html&gt;
  4. &lt;head&gt;
  5. &lt;meta charset=&quot;utf-8&quot;&gt;
  6. &lt;title&gt;{{.title}} - MySite&lt;/title&gt;
  7. &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;style.css&quot;&gt;
  8. &lt;/head&gt;
  9. {{end}}

header.html inside data folder

  1. {{define &quot;headerHTML&quot;}}
  2. &lt;header&gt;
  3. {{.header}}
  4. &lt;h1&gt;Welcome to my site!&lt;/h1&gt;
  5. &lt;br&gt;
  6. &lt;nav&gt;
  7. &lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;
  8. &lt;/nav&gt;
  9. &lt;/header&gt;
  10. {{end}}

footer.html inside data folder:

  1. {{define &quot;footerHTML&quot;}}
  2. &lt;h1&gt;Welcome! {{.footer}}&lt;/h1&gt;
  3. &lt;footer&gt;
  4. &lt;p&gt;Thank You for Visiting&lt;/p&gt;
  5. &lt;/footer&gt;
  6. &lt;/body&gt;
  7. &lt;/html&gt;
  8. {{end}}

And the code will be like this

  1. package main
  2. import (
  3. &quot;html/template&quot;
  4. &quot;io/ioutil&quot;
  5. &quot;net/http&quot;
  6. &quot;path/filepath&quot;
  7. &quot;strings&quot;
  8. )
  9. var tPath = &quot;./temps/&quot;
  10. var dPath = &quot;./data/&quot;
  11. var templateDirs = []string{&quot;temps&quot;, &quot;data&quot;}
  12. var templates *template.Template
  13. func getTemplates() (templates *template.Template, err error) {
  14. var allFiles []string
  15. for _, dir := range templateDirs {
  16. files2, _ := ioutil.ReadDir(dir)
  17. for _, file := range files2 {
  18. filename := file.Name()
  19. if strings.HasSuffix(filename, &quot;.html&quot;) {
  20. filePath := filepath.Join(dir, filename)
  21. allFiles = append(allFiles, filePath)
  22. }
  23. }
  24. }
  25. templates, err = template.New(&quot;&quot;).ParseFiles(allFiles...)
  26. return
  27. }
  28. func init() {
  29. templates, _ = getTemplates()
  30. }
  31. func rootHandler(wr http.ResponseWriter, req *http.Request) {
  32. title := &quot;home&quot;
  33. data := map[string]interface{}{
  34. &quot;title&quot;: title,
  35. &quot;header&quot;: &quot;My Header&quot;,
  36. &quot;footer&quot;: &quot;My Footer&quot;,
  37. }
  38. err := templates.ExecuteTemplate(wr, &quot;homeHTML&quot;, data)
  39. if err != nil {
  40. http.Error(wr, err.Error(), http.StatusInternalServerError)
  41. }
  42. }
  43. func main() {
  44. http.HandleFunc(&quot;/&quot;, rootHandler)
  45. http.ListenAndServe(&quot;:8080&quot;, nil)
  46. }

答案2

得分: 1

你需要将数据作为structmap传递给模板。以下是使用maprootHandler示例:

  1. func rootHandler(wr http.ResponseWriter, req *http.Request) {
  2. title := "home"
  3. //将变量包装到map中
  4. data := map[string]interface{}{
  5. "Title": title,
  6. "IntVar": 100,
  7. }
  8. err := templates.ExecuteTemplate(wr, title+".html", data)
  9. //其他代码...
  10. }

有关更多详细信息,请参阅文档

英文:

You need to pass the data as struct or map to template. Example of your rootHandler using map:

  1. func rootHandler(wr http.ResponseWriter, req *http.Request) {
  2. title := &quot;home&quot;
  3. //Wrap your variable into a map
  4. data := map[string]interface{}{
  5. &quot;Title&quot;: title,
  6. &quot;IntVar&quot;: 100,
  7. }
  8. err := templates.ExecuteTemplate(wr, title+&quot;.html&quot;, data)
  9. //other codes...
  10. }

For more details, see documentation.

答案3

得分: 1

接受的答案可以通过使用template.ParseGlob来简化。

将func getTemplates()的内容替换为:

  1. templates, err := template.ParseGlob("temps/*")
  2. if err != nil {
  3. return nil, err
  4. }
  5. return templates.ParseGlob("data/*")
英文:

The accepted answer can be simplified by using template.ParseGlob

Replace the contents of func getTemplates() with

  1. templates, err:= template.ParseGlob(&quot;temps/*&quot;)
  2. if err!= nil {
  3. return nil, err
  4. }
  5. return templates.ParseGlob(&quot;data/*)

huangapple
  • 本文由 发表于 2017年5月6日 10:22:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/43816039.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定