截止目前,我们的blog只有单个的页面,没有将其统一管理起来。要管理有两种方法,相信大家都见过:
- 首页,包含指向每部分内容的链接
- 导航栏,无论位于哪个页面,都有一个导航栏指向其他的页面
从blog的使用场景来说,导航栏更加使用,在阅读当前文章的同时,可以通过导航栏快速移动到其他专题。
1 设计思路
在每个页面的顶部添加一个导航栏,目前可以导航到博客,留言板和关于3个页面。后面按照需要扩展。
如果要在每个页面模板都新增这个模块,同样的内容需要修改的文件太多,后续调整导航栏和新增页面都太麻烦,因此我们需要一个框架模板,在框架模板里将所有页面中共有的内容(导航栏、css、js等)统一部署,每个功能页面只关注自己的功能就行,减少后续的开发量。
gin官方并不支持这种框架模板,但官方github上推荐了使用ez-gin-template这个包。其使用和源码解析见https://www.jianshu.com/p/a9c81e02e8f6。
2 框架模板
框架模板如下,主要有几个点:
- 从参数中解析本页的
title
- 添加公共属性和静态资源
- 引入模板
header
- 引入模板
content
,content
为页面的实际内容
<!DOCTYPE html>
<html>
<header>
<title>{{.Title}}</title>
<meta charset="utf8"/>
<link rel="stylesheet" type="text/css" href="../../static/css/common.css">
</header>
<body>
<div class="header">
{{template "header"}}
</div>
<div class="content">
{{template "content" .Content}}
</div>
</body>
</html>
3 header模板
header
模板实现了导航栏。
使用一个列表表示导航栏中的条目,将关于放置在页面的最右端:
{{define "header"}}
<ul class="navi">
<li class="navi_li active"><a class="navi_a" href="/article_list">博客</a></li>
<li class="navi_li"><a class="navi_a" href="/msgboard">留言板</a></li>
<li class="navi_li" style="float: right"><a class="navi_a" href="/about">关于</a></li>
</ul>
{{end}}
通过CSS将列表显示成导航栏的样子:
.footer-fixed {
position: fixed;
margin: 0;
padding: 0;
left: 0;
bottom: 0;
width: 1000px;
height: 50px;
margin-left: auto;
margin-right: auto;
}
ul.navi {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333333;
top: 0;
width: 100%;
height: 50;
}
li.navi_li {
float: left;
}
a.navi_a {
display: block;
width: 60px;
padding: 14px 16px;
color: white;
text-decoration: none;
text-align: center;
}
li.navi_li:hover {
background-color: #111111
}
4 以article_list模板为例的content
article_list
模板不再需要公共的部分,只需要描述文章列表的块中需要哪些内容。其模板名必须定义为在content
,因为我们在layout
模板中会加载名字为content
的模板。
{{ define "content"}}
<div class="article_list">
{{ if len .}}
<h2>Article List:</h2>
<ul>
{{ range . }}
<li><a href="/article/{{.ID}}">{{.Title}}</a></li>
{{ end }}
</ul>
{{ else }}
<p>当前没有文章 :( </p>
{{ end }}
</div>
{{end}}
article_list
模板的使用如下:
// ArticleListGet handle route to /article_list
func ArticleListGet(c *gin.Context) {
articles, err := service.ShowArticleList()
ctx := make(map[string]interface{})
ctx["Title"] = "博客列表"
ctx["Content"] = articles
if err != nil {
fmt.Println("get articles from db err", err)
c.String(http.StatusInternalServerError, err.Error())
}
c.HTML(http.StatusOK, "blogs/article_list", ctx)
}
和原来相比,有如下几点差异:
- 模板名从
article_list
变为了blogs/article_list
,因为ez-gin-template
会将每个模板名设置为配置的模板目录下的相对路径。 - 传入的参数不再是
articles
,而是包含了articles
和页面Title
的map
,因为layout
模板要根据Title
字段设置当前页面的标题,然后将Content
中的内容,即article
传递给article_list
模板解析。
5 使用ez-gin-template将所有内容组织起来
5.1 模板目录结构
-
layouts
目录中放置框架模板。 -
partials
目录中放置全局组件模板,当前是_header.html
模板,即导航栏。ez-gin-template
认为所有以"_"开头的模板文件作为组件模板,只会嵌入到其他模板中,而不会作为最终模板去解析。 -
blogs
目录中放置的就是我们最终要展示给用户的页面模板,所有页面都会嵌入到layout
模板后重新生成组合之后的模板,提供给gin
的HTML渲染模块。
模板目录结构
5.2 ez-gin-template配置
2-3行代码就完成了模板的组合和加载,可以使用了
import (
eztemp "github.com/michelloworld/ez-gin-template"
)
engine := gin.Default()
render := eztemp.New()
// 配置模板文件所在的目录
render.TemplatesDir = "template/"
// render.Layout = "layouts/base" // default
// render.Ext = ".html" // default
// 组合模板目录下的模板,并赋值给HTMLRender,以后的HTML渲染就使用新生成的组合模板
engine.HTMLRender = render.Init()
6 效果
文章列表留言板 关于
7 小结
今天通过使用ez-gin-template
模板实现了框架模板,并添加了导航类。 为后面的扩展省了很多工作。
ez-gin-template
通过140行代码实现了这样一个功能,其主要依靠对gin
的Render
模块的熟悉,将自己想要的东西嵌入到了里面。只要熟悉了Render
模块的原理,相信想要实现其他想法都不难。也就是行业常说的,程序员看代码和写代码的时间比例应该在10:1才比较合理。
我也是通过这次事件对Render
模块有了初步的了解,果然做事还是需要了解清楚需求,了解清楚背景,对症下药最省事。
ez-gin-template
的详解可以看上面给出的另外一篇文章。
网友评论