模板引擎

Beego 的模板处理引擎采用的是 Go 内置的 html/template 包进行处理,而且 Beego 的模板处理逻辑是采用了缓存编译方式,也就是所有的模板会在 Beego 应用启动的时候全部编译然后缓存在 map 里面。

模板目录

Beego 中默认的模板目录是 views,用户可以把模板文件放到该目录下,Beego 会自动在该目录下的所有模板文件进行解析并缓存,开发模式下每次都会重新解析,不做缓存。当然,用户也可以通过如下的方式改变模板的目录(只能指定一个目录为模板目录):

  1. web.ViewsPath = "myviewpath"

自动渲染

用户无需手动的调用渲染输出模板,Beego 会自动的在调用完相应的 method 方法之后调用 Render 函数,当然如果您的应用是不需要模板输出的,那么可以在配置文件或者在 main.go 中设置关闭自动渲染。

配置文件配置如下:

  1. autorender = false

或者在程序里面设置如下:

  1. web.AutoRender = false

模板标签

Go 语言的默认模板采用了 {{}} 作为左右标签,但是我们有时候在开发中可能界面是采用了 AngularJS 开发,他的模板也是这个标签,故而引起了冲突。在 Beego 中你可以通过配置文件或者直接设置配置变量修改:

  1. web.TemplateLeft = "<<<"
  2. web.TemplateRight = ">>>"

模板数据

模板中的数据是通过在 Controller 中 this.Data 获取的,所以如果你想在模板中获取内容,那么你需要在 Controller 中如下设置:

  1. this.Data["Content"] = "value"

对应的 HTML 内容是:

  1. {{ .Content }}

如何使用各种类型的数据渲染:

  • 结构体:结构体定义

    1. type A struct{
    2. Name string
    3. Age int
    4. }
  1. 控制器数据赋值
  2. this.Data["a"]=&A{Name:"astaxie",Age:25}
  3. 模板渲染数据如下:
  4. the username is {{.a.Name}} the age is {{.a.Age}}
  • map 控制器数据赋值

    1. mp["name"]="astaxie"
    2. mp["nickname"] = "haha"
    3. this.Data["m"]=mp
  1. 模板渲染数据如下:
  2. the username is {{.m.name}} the username is {{.m.nickname}}
  • slice

    控制器数据赋值

    1. ss :=[]string{"a","b","c"}
    2. this.Data["s"]=ss
  1. 模板渲染数据如下:
  2. {{range $key, $val := .s}} {{$key}} {{$val}} {{end}}

总结下来,可以看到.定位到了 Go 程序 Data 字段。而后 .xxx 则是定位到了 Data 包含的元素。

模板名称

Beego 采用了 Go 语言内置的模板引擎,所有模板的语法和 Go 的一模一样,至于如何写模板文件,详细的请参考 模板教程 (opens new window)

用户通过在 Controller 的对应方法中设置相应的模板名称,Beego 会自动的在 viewpath 目录下查询该文件并渲染,例如下面的设置,Beego 会在 admin 下面找 add.tpl 文件进行渲染:

  1. this.TplName = "admin/add.tpl"

我们看到上面的模板后缀名是tpl,Beego 默认情况下支持 tplhtml 后缀名的模板文件,如果你的后缀名不是这两种,请进行如下设置:

  1. web.AddTemplateExt("你文件的后缀名")

当你设置了自动渲染,然后在你的 Controller 中没有设置任何的 TplName,那么 Beego 会自动设置你的模板文件如下:

  1. c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt

也就是你对应的 Controller 名字+请求方法名.模板后缀,也就是如果你的 Controller 名是 AddController,请求方法是 POST,默认的文件后缀是 tpl,那么就会默认请求 /viewpath/AddController/post.tpl 文件。

Layout 设计

Beego 支持 layout 设计,例如你在管理系统中,整个管理界面是固定的,只会变化中间的部分,那么你可以通过如下的设置:

  1. this.Layout = "admin/layout.html"
  2. this.TplName = "admin/add.tpl"

layout.html 中你必须设置如下的变量:

  1. {{.LayoutContent}}

Beego 就会首先解析 TplName 指定的文件,获取内容赋值给 LayoutContent,然后最后渲染 layout.html 文件。

目前采用首先把目录下所有的文件进行缓存,所以用户还可以通过类似这样的方式实现 layout

  1. {{template "header.html" .}} Logic code {{template "footer.html" .}}

特别注意后面的.,这是传递当前参数到子模板

LayoutSection

对于一个复杂的 LayoutContent,其中可能包括有 javascript 脚本、CSS 引用等,根据惯例,通常 css 会放到 Head 元素中,javascript 脚本需要放到 body 元素的末尾,而其它内容则根据需要放在合适的位置。在 Layout 页中仅有一个 LayoutContent 是不够的。所以在 Controller 中增加了一个 LayoutSections属性,可以允许 Layout 页中设置多个 section,然后每个 section 可以分别包含各自的子模板页。

layout_blog.tpl:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Lin Li</title>
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  7. <link
  8. rel="stylesheet"
  9. href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"
  10. />
  11. <link
  12. rel="stylesheet"
  13. href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css"
  14. />
  15. {{.HtmlHead}}
  16. </head>
  17. <body>
  18. <div class="container">{{.LayoutContent}}</div>
  19. <div>{{.SideBar}}</div>
  20. <script
  21. type="text/javascript"
  22. src="http://code.jquery.com/jquery-2.0.3.min.js"
  23. ></script>
  24. <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
  25. {{.Scripts}}
  26. </body>
  27. </html>

html_head.tpl:

  1. <style>
  2. h1 {
  3. color: red;
  4. }
  5. </style>

scripts.tpl

  1. <script type="text/javascript">
  2. $(document).ready(function () {
  3. // bla bla bla
  4. });
  5. </script>

逻辑处理如下所示:

  1. type BlogsController struct {
  2. web.Controller
  3. }
  4. func (this *BlogsController) Get() {
  5. this.Layout = "layout_blog.tpl"
  6. this.TplName = "blogs/index.tpl"
  7. this.LayoutSections = make(map[string]string)
  8. this.LayoutSections["HtmlHead"] = "blogs/html_head.tpl"
  9. this.LayoutSections["Scripts"] = "blogs/scripts.tpl"
  10. this.LayoutSections["Sidebar"] = ""
  11. }

renderform 使用

定义 struct:

  1. type User struct {
  2. Id int `form:"-"`
  3. Name interface{} `form:"username"`
  4. Age int `form:"age,text,年龄:"`
  5. Sex string
  6. Intro string `form:",textarea"`
  7. }
  • StructTag 的定义用的标签用为 form,和 ParseForm 方法 共用一个标签,标签后面有三个可选参数,用 , 分割。第一个参数为表单中类型的 name 的值,如果为空,则以 struct field name 为值。第二个参数为表单组件的类型,如果为空,则为 text。表单组件的标签默认为 struct field name 的值,否则为第三个值。
  • 如果 form 标签只有一个值,则为表单中类型 name 的值,除了最后一个值可以忽略外,其他位置的必须要有 , 号分割,如:form:",,姓名:"
  • 如果要忽略一个字段,有两种办法,一是:字段名小写开头,二是:form 标签的值设置为 -
  • 现在的代码版本只能实现固定的格式,用 br 标签实现换行,无法实现 css 和 class 等代码的插入。所以,要实现 form 的高级排版,不能使用 renderform 的方法,而需要手动处理每一个字段。

controller:

  1. func (this *AddController) Get() {
  2. this.Data["Form"] = &User{}
  3. this.TplName = "index.tpl"
  4. }

Form 的参数必须是一个 struct 的指针。

template:

  1. <form action="" method="post">{{.Form | renderform}}</form>

上面的代码生成的表单为:

  1. Name: <input name="username" type="text" value="test"></br>
  2. 年龄:<input name="age" type="text" value="0"></br>
  3. Sex: <input name="Sex" type="text" value=""></br>
  4. Intro: <input name="Intro" type="textarea" value="">