模板引擎

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. this.Data["a"]=&A{Name:"astaxie",Age:25}

    模板渲染数据如下:

    1. 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. the username is {{.m.name}} the username is {{.m.nickname}}
  • slice

    控制器数据赋值

    1. ss :=[]string{"a","b","c"}
    2. this.Data["s"]=ss

    模板渲染数据如下:

    1. {{range $key, $val := .s}} {{$key}} {{$val}} {{end}}

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

模板名称

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

用户通过在 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="">