Gin模板渲染

Gin模板渲染

1 基本使用

gin框架的模板渲染 是基于 html/template包 实现的

第一步:index.html

在项目根路径下新建templates文件夹,文件夹内写模板文件,如index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第一个模板文件</title>
</head>
<body>
我的名字是:{{.name}}
<br>
我的年龄是:{{.age}}
</body>
</html>

第二步:渲染模板

Gin 框架中使用 c.HTML 可以渲染模板,渲染模板前需要使用 LoadHTMLGlob()或者 LoadHTMLFiles()方法加载模板

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	// 加载整个文件夹
	//router.LoadHTMLGlob("templates/*")
  	// 加载单个
	router.LoadHTMLFiles("templates/index.html", "templates/index2.html")
	router.GET("/index", func(c *gin.Context) {

		c.HTML(200,"index.html",gin.H{"name":"lxx","age":19})

	})
	router.Run(":8000")
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5VC4zb1t-1660637141459)(C:\Users\xihan\AppData\Roaming\Typora\typora-user-images\image-20220815154854658.png)]

2 模板文件放在不同文件夹下

Gin 框架中如果不同目录下面有同名模板的话我们需要使用下面方法加载模板
一旦templates文件夹下还有文件夹,一定要按给每一个都定义名字
注意:定义模板的时候需要通过 define 定义名称

templates/admin/index.html
{{ define "admin/index.html" }}
html内容
{{end}}

2.1 main.go

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	// 注意此处的导入路径  此时只注册了templates 下各个文件夹下的文件, tempates 下的文件未注册
	router.LoadHTMLGlob("templates/**/*")
	router.GET("/index", func(c *gin.Context) {
    // 模板名为新定义的模板名字
		c.HTML(200,"admin/index.html",gin.H{"title":"我是后台模板"})

	})
	router.Run(":8000")
}

2.2 admin/index.tmpl

{{ define "admin/index.tmpl" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>后台管理首页</title>
</head>
<body>
<h1>{{.title}}</h1>
</body>
</html>

{{end}}

2.3 目录结构为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TlecyVzV-1660637141461)(C:\Users\xihan\AppData\Roaming\Typora\typora-user-images\image-20220815155347592.png)]

2.4 注意

  1. 如果模板在多级目录里面的话需要这样配置 r.LoadHTMLGlob("templates/**/*") /**表示目录,/* 表示文件
  2. LoadHTMLGlob只能加载同一层级的文件

比如说使用router.LoadHTMLFile(/templates/**/*),就只能加载/templates/admin/或者/templates/xx/下面的文件
解决办法就是通过filepath.Walk来搜索/templates下的以.html结尾的文件,把这些html文件都加载一个数组中,然后用LoadHTMLFiles加载

var files []string
filepath.Walk("./templates", func(path string, info os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".html") {
			files = append(files, path)
		}
		return nil
	})
router.LoadHTMLFiles(files...)

3 模板语法

3.1 {{.}} 渲染变量

有两个常用的传入变量的类型。一个是struct,在模板内可以读取该struct的字段(对外暴露的属性)来进行渲染。还有一个是map[string]interface{},在模板内可以使用key获取对应的value来进行渲染

3.1.1 main.go
package main

import (
	"github.com/gin-gonic/gin"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	router := gin.Default()

	var files []string
	filepath.Walk("./templates", func(path string, info os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".html") {
			files = append(files, path)
		}
		return nil
	})
	router.LoadHTMLFiles(files...)

	router.GET("/index", func(c *gin.Context) {
		type Book struct {
			Name string
			price int
		}
		c.HTML(200, "order.html", gin.H{
			"age": 10,
			"name":"lxx",
			"hobby":[3]string{"抽烟","喝酒","烫头"},
			"wife":[]string{"刘亦菲","迪丽热巴","古力娜扎"},
			"info":map[string]interface{}{"height":180,"gender":"男"},
			"book":Book{"红楼梦",99},

		})

	})
	router.Run(":8000")
}
3.1.2 order.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>订单页面</title>
</head>
<body>
<h1>渲染字符串,数字,数组,切片,maps,结构体</h1>
<p>年龄:{{.age}}</p>
<p>姓名:{{.name}}</p>
<p>爱好:{{.hobby}}</p>
<p>wife:{{.wife}}</p>
<p>信息:{{.info}}--->{{.info.gender}}</p>
<p>图书:{{.book}}--->{{.book.Name}}</p>
</body>
</html>

3.2 注释

{{/* a comment */}}
// 注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止。
<p>图书不显示,注释了:{{/* .book */}}</p>

3.3 声明变量

<h1>声明变量</h1>
{{$obj := .book.Name}}
<p>{{$obj}}</p>

3.4 移除空格

{{符号的后面加上短横线并保留一个或多个空格来去除它前面的空白(包括换行符、制表符、空格等),即{{- xxxx

}}的前面加上一个或多个空格以及一个短横线-来去除它后面的空白,即xxxx -}}

<p>{{ 20 }} < {{ 40 }}---> 20 < 40</p>
<p>{{ 20 -}} < {{- 40 }}-->20<40</p>

3.5 比较函数

布尔函数会将任何类型的零值视为假,其余视为真。 下面是定义为函数的二元比较运算的集合:

eq  如果arg1 == arg2则返回真
ne  如果arg1 != arg2则返回真
lt  如果arg1 < arg2则返回真
le  如果arg1 <= arg2则返回真
gt  如果arg1 > arg2则返回真
ge  如果arg1 >= arg2则返回真
// 使用方式
<h1>比较函数</h1>
<p>{{gt 11 13}}</p>
<p>{{lt 11 13}}</p>
<p>{{eq 11 11}}</p>

3.6 条件判断

// 方式一
{{if pipeline}} T1 {{end}}
// 方式二
{{if pipeline}} T1 {{else}} T0 {{end}}
// 方式三
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}} 
<h1>条件判断</h1>
<br>//案例一
{{if .show}}
看到我了
{{end}}

<br>//案例二
{{if gt .age 18}}
成年了
{{else}}
没成年
{{end}}

<br>// 案例三
{{if gt .score 90}}
优秀
{{else if gt .score 60}}
及格
{{else}}
不及格
{{end}}

3.7 range循环

// 方式一
{{ range pipeline }} T1 {{ end }}

// 方式二
// 如果 pipeline 的长度为 0 则输出 else 中的内容
{{ range pipeline }} T1 {{ else }} T2 {{ end }}

range可以遍历slice、数组、map或channel。遍历的时候,会设置.为当前正在遍历的元素。

对于第一个表达式,当遍历对象的值为0值时,则range直接跳过,就像if一样。对于第二个表达式,则在遍历到0值时执行else。

range的参数部分是pipeline,所以在迭代的过程中是可以进行赋值的。但有两种赋值情况:

{{ range $value := pipeline }} T1 {{ end }}
{{ range $key, $value := pipeline }} T1 {{ end }}

如果range中只赋值给一个变量,则这个变量是当前正在遍历元素的值。如果赋值给两个变量,则第一个变量是索引值(array/slice是数值,map是key),第二个变量是当前正在遍历元素的值

<h1>range循环</h1>
<h2>循环数组</h2>
{{range $index,$value:=.wife}}
<p>{{$index}}---{{$value}}</p>
{{end}}
<h2>循环map</h2>
{{range $key,$value:=.info}}
<p>{{$key}}---{{$value}}</p>
{{end}}
<h2>循环空-->"girls":map[string]interface{}{}</h2>
{{range $value:=.girls}}
<p>{{$value}}</p>
{{else}}
没有女孩
{{end}}

3.8 with…end

{{ with pipeline }} T1 {{ end }}
{{ with pipeline }} T1 {{ else }} T0 {{ end }}

对于第一种格式,当pipeline不为0值的时候,将.设置为pipeline运算的值,否则跳过。
对于第二种格式,当pipeline为0值时,执行else语句块T0,否则.设置为pipeline运算的值,并执行T1。

<h1>with ... end</h1>
<h2>不使用with</h2>
<p>{{.book.Name}}</p>
<p>{{.book.Price}}</p>
<h2>使用with</h2>
{{with .book}}
<p>{{.Name}}</p>
<p>{{.Price}}</p>
{{end}}

3.9 函数

golang的模板其实功能很有限,很多复杂的逻辑无法直接使用模板语法来表达,所以只能使用模板函数来实现。

首先,template包创建新的模板的时候,支持.Funcs方法来将自定义的函数集合导入到该模板中,后续通过该模板渲染的文件均支持直接调用这些函数。

该函数集合的定义为:

type FuncMap map[string]interface{}

key为方法的名字,value则为函数。这里函数的参数个数没有限制,但是对于返回值有所限制。有两种选择,一种是只有一个返回值,还有一种是有两个返回值,但是第二个返回值必须是error类型的。这两种函数的区别是第二个函数在模板中被调用的时候,假设模板函数的第二个参数的返回不为空,则该渲染步骤将会被打断并报错

3.9.1 内置函数
var builtins = FuncMap{
	// 返回第一个为空的参数或最后一个参数。可以有任意多个参数。
	// "and x y"等价于"if x then y else x"
	"and": and,
	// 显式调用函数。第一个参数必须是函数类型,且不是template中的函数,而是外部函数。
	// 例如一个struct中的某个字段是func类型的。
	// "call .X.Y 1 2"表示调用dot.X.Y(1, 2),Y必须是func类型,函数参数是1和2。
	// 函数必须只能有一个或2个返回值,如果有第二个返回值,则必须为error类型。
	"call": call,
	// 返回与其参数的文本表示形式等效的转义HTML。
	// 这个函数在html/template中不可用。
	"html": HTMLEscaper,
	// 对可索引对象进行索引取值。第一个参数是索引对象,后面的参数是索引位。
	// "index x 1 2 3"代表的是x[1][2][3]。
	// 可索引对象包括map、slice、array。
	"index": index,
	// 返回与其参数的文本表示形式等效的转义JavaScript。
	"js": JSEscaper,
	// 返回参数的length。
	"len": length,
	// 布尔取反。只能一个参数。
	"not": not,
	// 返回第一个不为空的参数或最后一个参数。可以有任意多个参数。
	// "or x y"等价于"if x then x else y"。
	"or":      or,
	"print":   fmt.Sprint,
	"p
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值