十九:GO编程

您所在的位置:网站首页 模板加载 十九:GO编程

十九:GO编程

2024-05-24 06:43| 来源: 网络整理| 查看: 265

Gin模板4.1 、Template模板语法4.1.1、基本示例

以下为test.html文件的内容,里面使用了一个template语法{{.}}。

DOCTYPE html> Title {{ . }}

以下是test.html同目录下的一个go web程序:

package main import ( "html/template" "net/http" ) func tmpl(w http.ResponseWriter, r *http.Request) { t1, err := template.ParseFiles("test.html") if err != nil { panic(err) } t1.Execute(w, "hello yuan") } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/index", tmpl) server.ListenAndServe() }

前面的html文件中使用了一个template的语法{{.}},这部分是需要通过go的template引擎进行解析,然后替换成对应的内容。

在go程序中,handler函数中使用template.ParseFiles("test.html"),它会自动创建一个模板(关联到变量t1上),并解析一个或多个文本文件(不仅仅是html文件),解析之后就可以使用Execute(w,"hello world")去执行解析后的模板对象,执行过程是合并、替换的过程。例如上面的{{.}}中的.会替换成当前对象"hello world",并和其它纯字符串内容进行合并,最后写入w中,也就是发送到浏览器"hello world"。

示例中{{.}},这个点是顶级作用域范围内的,它代表Execute()的第二个参数。4.1.1、变量渲染

视图部分:

package main import ( "fmt" "html/template" "net/http" ) // main.go type Student struct { Name string // 注意大小写 Gender string Age int Courses []string } func index(w http.ResponseWriter, r *http.Request) { // 1、解析指定文件生成模板对象 tmpl, err := template.ParseFiles("templates/index.html") if err != nil { fmt.Println("create template failed, err:", err) return } // 2、利用给定数据渲染模板,并将结果写入w // obj1:=Student{"yuan","male",23} s1 := Student{"yuan", "male", 23,[]string{"chinese","math","english"}} obj := map[string]interface{}{ "s1": s1, "books": []string{"三国演义", "西游记", "红楼梦", "金瓶梅"}, "articles": []string{}, } tmpl.Execute(w, obj) } func main() { http.HandleFunc("/", index) err := http.ListenAndServe(":8080", nil) if err != nil { fmt.Println("HTTP server failed,err:", err) return } } (1) 深度查询句点符.

hi,{{.}}

姓名: {{.Name}}

年龄: {{.Age}}

性别: {{.Gender}}

{{.s1}}

{{.s1.Name}}

{{.s1.Courses}}

{{.books}}

{{index .books 2}}

range、with、if等内置action都有自己的本地作用域。(2) 管道pipeline

pipeline是指产生数据的操作。比如{{.}}、{{.Name}}、funcname args等。

可以使用管道符号|链接多个命令,用法和unix下的管道类似:|前面的命令将运算结果(或返回值)传递给后一个命令的最后一个位置。

例如:

{{.s1.Age|printf "姓名:%s\n 年龄:%v" "yuan"}} 需要注意的是,并非只有使用了|才是pipeline。Go template中,pipeline的概念是传递数据,只要能产生数据的,都是pipeline。这使得某些操作可以作为另一些操作内部的表达式先运行得到结果,就像是Unix下的命令替换一样。{{println (len "yuan")}} (3) 条件判断{{if pipeline}} T1 {{end}} {{if pipeline}} T1 {{else}} T0 {{end}} {{if pipeline}} T1 {{else if pipeline}} T0 {{end}}表达式为false的情况是各种数据对象的0值:数值0,指针或接口是nil,数组、slice、map或string则是len为0。{{if .articles }} {{.articles}} {{else}}

没有任何文章

{{end}}(4) range循环{{range $value := .}} {{range $key,$value := .}}如果range中只赋值给一个变量,则这个变量是当前正在迭代元素的值。如果赋值给两个变量,则第一个变量是索引值(map/slice是数值,map是key),第二个变量是当前正在迭代元素的值。变量名以$开头

{{range $index,$value := .books}}

{{$index}} : {{$value}}

{{end}} {{range $index,$value := .s1.Courses}}

{{$index}} : {{$value}}

{{end}}(5) with语句{{with .s1}}

{{.Name}}

{{.Age}}

{{end}}(6) 注释

注释方式:{{/* a comment */}}。注释后的内容不会被引擎进行替换。但需要注意,注释行在替换的时候也会占用行,所以应该去除前缀和后缀空白,否则会多一空行。

{{- /* this line is a comment */}}(7) 变量赋值

可以在template中定义变量:

// 未定义过的变量 $var := pipeline // 已定义过的变量 $var = pipeline4.1.2、GIn的模板函数(1)默认模板函数

语法格式:

functionName [Argument...]

Argument参数是可选的,如果有多个参数,参数直接用空格分隔。

(2)自定义模板函数

视图部分:

package main import ( "fmt" "html/template" "net/http" ) func index(w http.ResponseWriter, r *http.Request) { // 1、解析指定文件生成模板对象 t1 := template.New("index.html") t1.Funcs(funcMap).ParseFiles("templates/index.html") t1.Execute(w, nil) } // 自定义模板函数: func add(x int, y int) int { return x + y } // 将自定义模板其添加到FuncMap结构中,并将此函数命名为"add",以后在待解析的内容中就可以调用"add"函数。 var funcMap = template.FuncMap{ "add": add, } func main() { http.HandleFunc("/", index) err := http.ListenAndServe(":8099", nil) if err != nil { fmt.Println("HTTP server failed,err:", err) return } }

模板部分:

{{add 2 3}} 4.1.3、Go模板的嵌套与继承(1) 嵌套:define和template

在实际项目中,我们不可能只有一个模板,一般来说都有很多个模板,而且这些模板也会共享一些公共的模板,这些公共的模板我们都可以定义成子模板,在需要的时候调用子模板,就可以将子模板的内容嵌入当前模板中。

提示:在项目中使用子模板,可以让项目模板具有模块化的能力,提高模块复用能力和可维护性。

define可以直接在待解析内容中定义一个模板,定义了模板之后,可以使用template这个action来执行模板。template有两种格式:

{{template "name"}} {{template "name" pipeline}}

第一种是直接执行名为name的template,点设置为nil。第二种是点".“设置为pipeline的值,并执行名为name的template。可以将template看作是函数:

template("name) template("name",pipeline)

示例:

t1.html文件内容如下:

Go Web Programming This is t1.html before This is the value of the dot in t1.html - [{{ . }}] {{ template "t2.html" }} This is t1.html after

因为内部有{{template "t2.html"}},且此处没有使用define去定义名为"t2.html"的模板,所以需要加载解析名为t2.html的文件。t2.html文件内容如下:

This is t2.html This is the value of the dot in t2.html - [{{ . }}]

处理这两个文件的handler函数如下:

func process(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("t1.html", "t2.html") t.Execute(w, "Hello World!") }

上面也可以不额外定义t2.html文件,而是直接在t1.html文件中使用define定义一个模板。修改t1.html文件如下:

Go Web Programming This is t1.html before This is the value of the dot in t1.html - [{{ . }}] {{ template "t2.html" }} This is t1.html after {{define "t2.html"}} This is t2.html This is the value of the dot in t2.html - [{{ . }}] {{end}}

然后在handler中,只需解析t1.html一个文件即可。

func process(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("t1.html") t.Execute(w, "Hello World!") }(2) 继承:block块

根据官方文档的解释:block等价于define定义一个名为name的模板,并在"有需要"的地方执行这个模板,执行时将”.“设置为pipeline的值。

但应该注意,block的第一个动作是执行名为name的模板,如果不存在,则在此处自动定义这个模板,并执行这个临时定义的模板。换句话说,block可以认为是设置一个默认模板。

例如:

{{block "T1" .}} one {{end}}

它首先表示{{template "T1" .}},也就是说先找到T1模板,如果T1存在,则执行找到的T1,如果没找到T1,则临时定义一个{{define "T1"}} one {{end}},并执行它。

下面是正常情况下不使用block的示例。

home.html文件内容如下:

Go Web Programming {{ template "content" }}

在此文件中指定了要执行一个名为"content"的模板,但此文件中没有使用define定义该模板,所以需要在其它文件中定义名为content的模板。现在分别在两个文件中定义两个content模板:

red.html文件内容如下:

{{ define "content" }} Hello World! {{ end }}

blue.html文件内容如下:

{{ define "content" }} Hello World! {{ end }}

在handler中,除了解析home.html,还根据需要解析red.html或blue.html:

func process(w http.ResponseWriter, r *http.Request) { rand.Seed(time.Now().Unix()) t := template.New("test") if rand.Intn(10) > 5 { t, _ = template.ParseFiles("home.html", "red.html") } else { t, _ = template.ParseFiles("home.html", "blue.html") } t.Execute(w,"") }

如果使用block,那么可以设置默认的content模板。例如将原本定义在blue.html中的content设置为默认模板。

修改home.html:

Go Web Programming {{ block "content" . }} Hello World! {{ end }}

然后修改handler:

func process(w http.ResponseWriter, r *http.Request) { rand.Seed(time.Now().Unix()) t := template.New("test") if rand.Intn(10) > 5 { t, _ = template.ParseFiles("home.html", "red.html") } else { t, _ = template.ParseFiles("home.html") } t.Execute(w,"") }

当执行else语句块的时候,发现home.html中要执行名为content的模板,但在ParseFiles()中并没有解析包含content模板的文件。于是执行block定义的content模板。而执行非else语句的时候,因为red.html中定义了content,会直接执行red.html中的content。

block通常设置在顶级的根文件中,例如上面的home.html中。

(3) 继承案例package main import ( "fmt" "net/http" "html/template" ) // main.go func index(w http.ResponseWriter, r *http.Request) { fmt.Println("index...") // 1、解析指定文件生成模板对象 tmpl, err := template.ParseFiles("./templates/layout.html","./templates/index.html","./templates/ads.html") if err != nil { fmt.Println("create template failed, err:", err) return } // 2、利用给定数据渲染模板,并将结果写入w err = tmpl.ExecuteTemplate(w,"index.html",nil) if err != nil { fmt.Println("render template failed, err:", err) return } } func archives(w http.ResponseWriter, r *http.Request) { fmt.Println("achives...") // 1、解析指定文件生成模板对象 tmpl, err := template.ParseFiles("./templates/layout.html","./templates/archives.html","./templates/ads.html") if err != nil { fmt.Println("create template failed, err:", err) return } // 2、利用给定数据渲染模板,并将结果写入w err = tmpl.ExecuteTemplate(w,"archives.html",nil) if err != nil { fmt.Println("render template failed, err:", err) return } } func main() { http.HandleFunc("/index", index) http.HandleFunc("/archives", archives) err := http.ListenAndServe(":6677", nil) if err != nil { fmt.Println("HTTP server failed,err:", err) return } }

templates/layout.html

Title *{ margin: 0; padding: 0; } .header{ width: 100%; background-color: #369; color: white; line-height: 48px; } .content{ margin-top: 10px; } yuan老师的个人博客 文章分类 Panel content 文章标签 Panel content 其它 Panel content {{block "content" .}} {{end}} {{/*模板嵌套*/}} {{template "ads.html"}}

templates/index.html,templates/article_detail.html,templates/archives.html

// index.html {{template "layout.html" .}} {{define "content"}} Hello index !!! {{end}} // archives.html {{template "layout.html" .}} {{define "content"}} Hello archievs!!! {{end}} tmpl, err := template.ParseFiles("./templates/layout.html","./templates/index.html","./templates/archives.html","./templates/ads.html") 这样的解析会发生覆盖行为,即最后的content会覆盖前面的content。

模板解析原理

4.2、Gin模板语法4.2.1、基本渲染语法Gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据,本质上就是字符串替换Gin框架中使用LoadHTMLGlob()或者LoadHTMLFiles()方法进行HTML模板渲染。

将template的渲染数据的案例转换为gin版本,模板不变:

package main import ( "github.com/gin-gonic/gin" "net/http" ) // main.go type Student struct { Name string // 注意大小写 Gender string Age int Courses []string } func index(c *gin.Context) { s1 := Student{"yuan", "male", 23,[]string{"chinese","math","english"}} c.HTML(http.StatusOK, "index.html", gin.H{ "s1": s1, "books": []string{"三国演义", "西游记", "红楼梦", "金瓶梅"}, "articles": []string{}, }) } func main() { r := gin.Default() // 返回一个html页面 r.LoadHTMLGlob("templates/*") r.GET("/index",index) r.Run() // 监听并在 0.0.0.0:8080 上启动服务 } 4.2.2、自定义模板函数func main() { router := gin.Default() router.SetFuncMap(template.FuncMap{ "add": func(x, y int) int { return x + y }, }) // 返回一个html页面 router.LoadHTMLGlob("templates/*") router.GET("/index", index) router.Run() // 监听并在 0.0.0.0:8080 上启动服务 } 4.2.3、模板嵌套与继承

Gin框架默认都是使用单模板,如果需要使用block template功能,可以通过"https://github.com/gin-contrib/multitemplate"库实现,具体示例如下:

base.html

Theme Template for Bootstrap Toggle navigation Bootstrap theme Home About Contact Dropdown Action Another action Something else here Nav header Separated link One more separated link {{block "content" .}} {{end}} window.jQuery || document.write('')

index.html

{{template "base.html" .}} {{define "content"}} 首页 {{end}}

archives.html

{{template "base.html" .}} {{define "content"}} 文章归类 {{end}}

main.go

package main import ( "github.com/gin-contrib/multitemplate" "github.com/gin-gonic/gin" "net/http" ) func index(c *gin.Context) { c.HTML(http.StatusOK, "index", gin.H{}) } func archives(c *gin.Context) { c.HTML(http.StatusOK, "archives", gin.H{}) } func createMyRender() multitemplate.Renderer { r := multitemplate.NewRenderer() r.AddFromFiles("index", "templates/base.html", "templates/index.html") r.AddFromFiles("archives", "templates/base.html", "templates/archives.html") return r } func main() { router := gin.Default() // 返回一个html页面 // router.LoadHTMLGlob("templates/*") // 继承会发生block覆盖 router.HTMLRender = createMyRender() router.GET("/", index) router.GET("/archives", archives) router.Run() // 监听并在 0.0.0.0:8080 上启动服务

下一篇:赋能圈:十九:GO编程-Gin框架-Gin模板

原文作者:Yuan原文链接:http://www.yuan316.com/post/Go%E8%AF%AD%E8%A8%80/



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3