ijd8.COM

A simple blog for an old Ma Nong.

Golang 超快模版 quicktemplate 入门及实践

Permalink

在 quicktemplate 刚开源时就关注,只是当时觉得太麻烦了,没有去尝试,现在刚好有兴趣试试,发现不但没那么难,而且还很方便,顺便记一点快速入门及实践经验。

语法

这个 blog 程序模版用 quicktemplate 实现下来用得最多的就下面几个标签:

  • {% if true %} abc {% endif %}
  • {% for k, v := range slice %} {%d k %} {%s v %} {% endfor %}
  • 字符类型 {%s str %}{%s= str %}
  • 数字类型 {%d number %}

数字类型多一点,习惯了也不难

plaintext: 数字类型
1
2
3
{%d int %} and {%dl int64 %} {%dul uint64 %} for integers.
{%f float %} for float64. Floating point precision may be set 
via {%f.precision float %}. For example, {%f.2 1.2345 %} outputs 1.23.

实践

模版文件 qtpl 存放在 model 文件夹,因为要在 handle 要调用 modle ,模版文件里的脚本可以直接使用同个文件夹里定义的 struct,不需要另外导入,避免相互导入。

文件结构

新建一个 qtpl 文件,如 base_page.qtpl

首先要定义一个 interface,如:

Go: page interface
1
2
3
4
5
6
7
8
{% interface
Page {
	Header()
	Body()
	Aside()
	Footer()
}
%}

再写一个函数:

Go: PageTemplate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{% func PageTemplate(p Page) %}
<html>
	<head>
		{%= p.Header() %}
	</head>
	<body>
	<article>
		{%= p.Body() %}
	</article>
	<aside>
		{%= p.Aside() %}
	</aside>
	<footer>
		{%= p.Footer() %}
	</footer>
	</body>
</html>
{% endfunc %}

这个是定义一个 layout 页面,没有变量的内容块都可以写在里面,比如 header 里面的静态内容等可以添加进去:

HTML: header
1
2
3
4
5
6
<head>
    <meta charset="utf-8">
    <meta content="True" name="HandheldFriendly" />
    <script src="/static/js/jquery.min.js" type="text/javascript"></script>
    {%= p.Header() %}
</head>

这个函数是在 handle 里调用 model.WritePageTemplate(ctx, p)

接下来定义基本页 basePage struct 包含所有页面的用到的属性,如:

Go: BasePage struct
1
2
3
4
5
6
BasePage struct {
    Title          string
    Keywords       string
    Description    string
    Canonical      string
}

紧接着定义 BasePage 的方法

Go: BasePageHeader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{% func (p *BasePage) Header() %}
<title>{%s p.Title %}</title>
<meta name="description" content="{%s p.Description %}">
<meta name="keywords" content="{%s p.Keywords %}">
<link rel="canonical" href="{%s p.Canonical %}">
{% endfunc %}

{% func (p *BasePage) Body() %}
This is a base body
{% endfunc %}

{% func (p *BasePage) Aside() %}
This is a base aside
{% endfunc %}

{% func (p *BasePage) Footer() %}
This is a base Footer
{% endfunc %}

内容可以随便写,也可以写具体的,如何选择,看个人情况。原则是 BasePage struct 里面有的数据都尽量满上,比如说一个网站的页头Header、边栏Aside、页脚Footer都相同,只有主体Body不同,那应该把Header、Aside、Footer 的内容都填写完整,并且 BasePage struct 里面应该包含 Header、Aside、Footer 所需要的所有属性、变量,这样可以避免多次重复的定义。

上面的内容都可以放在 base_page.qtpl 文件里。

以后所有的页面都继承这个 struct,只需添加对应的属性。以首页为例:

建立一个 home_page.qtpl 文件

Go: HomePage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 这外面的文字随便写,可以当注释,不会参与编译,行头可以不用加斜杠,这里加只为代码高亮显示美观
// 定义一个 HomePage 继承 BasePage,同时添加首页列表需要的 NewsList (这只是举例)

{% code
type HomePage struct {
    BasePage
    NewsList   []NewsStruct
}
%}


// 然后写一个方法覆盖 Body 内容
{% func (p *HomePage) Body() %}

<ul>

{% for _, item := range p.NewsList %}
<li><a href="/news/{%d item.ID %}">{%s item.Title %}</a></li>
{% endfor %}

</ul>

{% endfunc %}


// 如果想改变边栏Aside 内容就写

{% func (p *HomePage) Aside() %}
这是首页的侧栏内容
{% endfunc %}

在 handle 里调用

Go: 调用
1
2
3
4
5
p := &model.HomePage{}

model.WritePageTemplate(ctx, p)
ctx.SetContentType("text/html; charset=utf-8") // 这行也很关键,否则默认下载文件

主体搞定,其它页照葫芦画瓢

当有页面改动时都需要在 modle 文件夹下敲一个命令 qtc,然后运行程序看看,只要编译过就可以稳定运行。

总结

模版的渲染速度相对数据的读取来说所用时间可以忽略不计,如果不对性能有很高要求,选择适合自己习惯就好,个人觉得 quicktemplate 入门较难,很不适应,一旦入门后会很喜欢这种写模版的方式。

感谢 quicktemplate 项目 https://github.com/valyala/quicktemplate

Write a Comment

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.16.5 Processed in 1ms