ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
Orange 的视图基于官方 `html/template` 和 `text/template` 包,基本用法也和官方包一致; 控制器 app.Context 和 view 包进行交互,http 渲染输出由 app.Context 中的方法处理,具体渲染模版替换由 view 包进行处理。 ## 建议 Golang 作为高性能,一切从简单出发的编程变成语言,更多的服务于微服务相关应用,目前更多的是提供Api接口服务,模板渲染作为php5时代的产物以逐渐被前后端分离思想、vue、react等大前端所取代,这样能让后端开发更多的去关注服务本身,而不用再关注前端交互。 基于这样的大背景,Orange 仅提供对 template 原生包的简易封装,能满足简单的模板渲染需求,如有更为复杂的的模板渲染需求,可以直接使用类似这一类的模板渲染包来实现 [goview](https://github.com/foolin/goview)。 ## 模版定义 视图包含应用的 HTML,并且将控制器 / 应用程序逻辑与演示逻辑分开。视图文件默认存放于 `storage/views` 目录下所有`.tpl`后缀的文件中,存放目录具体配置可以在 `config/config/toml` 中进行调整。 ``` [app] ... viewPath = "./storage/views" ``` 一个简单的视图如下所示: ``` <!-- 此视图文件位置: storage/views/hello.tpl --> <html> <body> <h1>Hello, {{.Name}}</h1> </body> </html> ``` 在控制器中通过 `app.Context` 中的 `ViewHtml` 或 `ViewText` 方法进行渲染; ~~~ func ViewShow(c *app.Context) error { showData := struct { Name string }{ Name : "world!", } return c.ViewHtml("hello", showData) } ~~~ 当然,视图文件也可以嵌套在 storage/views 目录的子目录中。「点」符号可以用来引用嵌套视图;如果你的视图存储在 storage/views/home/index.tpl,则可以这样引用它: ``` return c.ViewHtml("home.index", showData) ``` ## 向视图传递数据 如上述例子所示,你可以使用结构体对象将数据传递到视图: ``` return c.ViewHtml("home.index", showData) ``` 此方式传递数据时,作为第二个参数的数据必须是结构体类型或 map[string]interface{} 类型; ## 获取渲染内容 有些时候我们不想直接输出模板内容,而是希望对内容再进行一些处理后输出,可以直接调用 view 包中的方法获取模板渲染后的内容。 ~~~ import "gitee.com/zhucheer/orange/view" ... tmpl := view.ContextTmpl(viewName).Assigns(viewData) htmlRes, err := tmpl.Render() ~~~ 该方法直接获取模版渲染后内容字符串,处理逻辑有可开发人员自行处理,更新灵活。 ## 模版引入 有些时候我们在定义模版时有些部分是可以共用的,比如后台中的 header footer 部分模版可以将公共的部分拆分出来定义成一个个单独的模板文件,在需要的地方进行 include 处理; 完成该功能需要2步: 1.定义引入模板 我们拆分出来的模板放到视图目录(views/),如下: 我们定义一个公用的样式模板,放到 ./views/layout/baseStyle.tpl 下; 定义引入模版时需要添加 define 标记 ~~~ {{define "baseStyle"}} <style> .redTitle{ font-size: 18px; color:#ff0000;} </style> {{end}} ~~~ 然后我们在 控制器或中间件中将该模板进行申明: ~~~ func ActionName(c *app.Context) error { // 同样以「点」分割目录形式输入指定的模板片段文件 c.AddIncludeTmpl("layout.baseStyle") } ~~~ 2.模板引入 我们在渲染模板时,将该公用的样式引入通过如下标记: ~~~ // 引用时使用 define定义的变量名 {{template "baseStyle" .}} ~~~ ## 模版引擎 模板引擎基于官方包[html/template](https://studygolang.com/static/pkgdoc/pkg/html_template.htm) 和 [`text/template](https://studygolang.com/static/pkgdoc/pkg/text_template.htm) 语法操作也是一样。 ### 变量替换 ~~~ func ViewShow(c *app.Context) error { showData := struct { Name string }{ Name : "world!", } return c.ViewHtml("hello", showData) } ... 视图文件: <html> <body> <h1>Hello, {{.Name}}</h1> </body> </html> ~~~ 视图文件中的 `{{.Name}}` 将会替换成 `world!` ### 系统变量 目前包如下系统变量: {{.CSRF_TOKEN}} 表单提交 csrf_token 数据 {{.REQUEST_REFERER}} 页面请求来源数据 ### 原样输出 `ViewHtml` 方法会对变量中的 html 内容进行转义防止 js 注入等安全问题,如果我们在确保安全的情况下希望原样输出 html 内容,可以使用模版内置函数进行处理; ``` <html> <body> <h1>Hello, {{.Name|unescaped}}</h1> </body> </html> ``` ### 模板注释 ~~~ {{/* a comment */}} 注释,执行时会忽略,可以多行;注释不能嵌套,并且必须紧贴分界符始止,就像这里表示的一样。 ~~~ ### if 条件判断 最简单的bool类型和字符串类型的判断 ``` {{if .condition}} {{end}} ``` 当.condition为bool类型的时候,则为true表示执行,当.condition为string类型的时候,则非空表示执行。 **else if嵌套用法** ``` {{if .condition1}} {{else if .contition2}} {{end}} ``` **eq 等于** {{if eq .var1 .var2}} {{end}} **ne 不等于** {{if ne .var1 .var2}} {{end}} **lt 小于 (less than)** {{if lt .var1 .var2}} {{end}} **le 小于等于** {{if le .var1 .var2}} {{end}} **gt 大于** {{if gt .var1 .var2}} {{end}} **ge 大于等于** {{if ge .var1 .var2}} {{end}} ### 循环遍历 template 还支持 range 循环来遍历 map、slice 内的内容,在模板内定义变量需要加上`$`符号 语法为: {{range $i,$v := .slice}} {{end}} ~~~ showData := struct { ItemArr []int }{ ItemArr: []int{1, 2, 3, 4, 5}, } return c.ViewHtml("home.index", showData) ... <ul> {{range $i, $v: = .ItemArr}} <li>list item {{$i}}=>{{$v}}</li> {{end}} </ul> ~~~