Golang的Web应用程序模板

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

Golang templates for web application

问题

我正在使用GoLang编写一个Web应用程序,不使用任何框架。

我正在尝试创建一个类似于Node.js中的布局(layout)的东西,例如。

=== layout.html ====

 {{ define "layout"}}
 <!DOCTYPE html>
 <html>
  <head>
  <meta charset='utf-8'>
    <link href="/static/style.css" rel="stylesheet" media="all" type="text/css">
   </head>
   <body>
     {{ template "content"}}
   </body>
</html>

{{ end }}

然后我在home.html中有一些内容

{{ define "content"}}
    <h1>{{.Title}}</h1>
    <div>This is a test</div>
{{ end }}

我对这种方法有两个问题

(1)我的Execute模板代码似乎没有将数据传递给content

templates.ExecuteTemplate(w, "layout", &Page{Title: "Home", Body: nil})

(2)如果我想要有多个页面使用相同的布局,上述方法将无法工作,因为它没有指定要加载哪个内容。

有人可以解释一下在GoLang中使用模板和布局的策略吗?

英文:

I am writing a web application in GoLang, not using any framework.

I am trying to create a layout similar to layouts in nodejs, for example.

=== layout.html ====

 {{ define &quot;layout&quot;}}
 &lt;!DOCTYPE html&gt;
 &lt;html&gt;
  &lt;head&gt;
  &lt;meta charset=&#39;utf-8&#39;&gt;
    &lt;link href=&quot;/static/style.css&quot; rel=&quot;stylesheet&quot; media=&quot;all&quot; type=&quot;text/css&quot;&gt;
   &lt;/head&gt;
   &lt;body&gt;
     {{ template &quot;content&quot;}}
   &lt;/body&gt;
&lt;/html&gt;

{{ end }}

I then have my some content in say home.html

{{ define &quot;content&quot;}}
    &lt;h1&gt;{{.Title}}&lt;/h1&gt;
    &lt;div&gt;This is a test&lt;/div&gt;
{{ end }}

I have 2 problems with this approach

(1) my Execute template code, does not seem to be passing the data to the content

templates.ExecuteTemplate(w, &quot;layout&quot;, &amp;Page{Title: &quot;Home&quot;, Body: nil})

(2) If I want to have multiple pages with the same layout, the above will not work as it does not specify which content to load.

Can someone please explain a strategy for using tempates and 'layouts' in GoLang ?

答案1

得分: 1

(1) 我的执行模板代码似乎没有将数据传递给内容。

正如评论中提到的,你需要显式地使用数据调用模板:

{{ template "content" . }}

注意在 content 部分之后的点号。

(2) 如果我想要有多个具有相同布局的页面,上述方法将不起作用,因为它没有指定要加载的内容。

你可以通过几种方式解决这个问题。我通常这样做。我不在每个模板中使用 {{ define "content" }},而是将所有模板解析为一个:

tmpls, err := template.ParseGlob(tmplGlob)

然后对于每个请求,我克隆布局并将所需的模板设置为 content

func executeTemplate(tmpls *template.Template, tmplName string, w io.Writer, data interface{}) error {
    var err error
    layout := tmpls.Lookup("layout.html")
    if layout == nil {
        return errNoLayout
    }

    layout, err = layout.Clone()
    if err != nil {
        return err
    }

    t := tmpls.Lookup(tmplName)
    if t == nil {
        return errNoTemplate
    }

    _, err = layout.AddParseTree("content", t.Tree)
    if err != nil {
        return err
    }

    return layout.Execute(w, data)
}
英文:

>(1) my Execute template code, does not seem to be passing the data to the content

As people have noted in the comments, you need to explicitly call the template with the data:

{{ template &quot;content&quot; . }}

Notice the dot after the &quot;content&quot; part.

>(2) If I want to have multiple pages with the same layout, the above will not work as it does not specify which content to load.

There are a few ways you can solve this. What I do is this. I don't {{ define &quot;content&quot; }} in every template. Instead I parse all templates into one:

tmpls, err := template.ParseGlob(tmplGlob)

And then for each request I clone the layout and set the desired template to &quot;content&quot;:

func executeTemplate(tmpls *template.Template, tmplName string, w io.Writer, data interface{}) error {
	var err error
	layout := tmpls.Lookup(&quot;layout.html&quot;)
	if layout == nil {
		return errNoLayout
	}

	layout, err = layout.Clone()
	if err != nil {
		return err
	}

	t := tmpls.Lookup(tmplName)
	if t == nil {
		return errNoTemplate
	}

	_, err = layout.AddParseTree(&quot;content&quot;, t.Tree)
	if err != nil {
		return err
	}

	return layout.Execute(w, data)
}

答案2

得分: 0

(2)如果我想要多个具有相同布局的页面,上述方法将无法工作,因为它没有指定要加载哪个内容。

你需要为此构建一些东西。

可以使用template func,它了解模板,接收块名称和调用t.executeTemplate的参数,就像你之前做的那样。

但是这种方法有一个严重的缺点,它要求每个请求都生成自己的编译模板。

也可以将其作为视图参数的方法。这样可以让你只构建一次模板,然后在每个请求中重复使用该实例,只是参数会改变。

无论如何,如果你继续使用内置的template助手,它不能是一个变量,它只能使用静态字符串。

英文:

> (2) If I want to have multiple pages with the same layout, the above will not work as it does not specify which content to load.

You need to build something for that matter.

It can be a template func, which knows the template, receives the block name and the args to call for t.executeTemplate, somehow like you did.

But this method has a severe drawback, as it requires that every request produces its own compiled template.

It can be a method of the view args. Which can let you build the template once, re use this instance for every request, only the argument will change.

No matter what, if you keep using the built in template helper it can t be a variable, it is locked to use only static string.

huangapple
  • 本文由 发表于 2016年11月10日 20:11:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/40527321.html
匿名

发表评论

匿名网友

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

确定