自定义函数
若是觉得模板中的预定义函数不够用,这时候就需要定义自己的函数了。
我们一般不在模板中定义自己的函数,而是在渲染模板之前给定自己所定义的函数,这将使用了Fancs方法。
scold := func(a string) string { return a + "TNND" } // 这个New就是用给的这个名字重新分配一个模板 // 调用Funcs方法前要先调用New方法 t, err := template.New("test").Funcs(template.FuncMap{"scold" : scold}).Parse
Funcs方法:
// 可以看出,在Funcs中要传入一个 map[string]interface{} , // 其中是string代表的自定义的方法在模板中叫啥名 // 第二个空接口穿的应该是自定义的函数 func (t *Template) Funcs(funcMap FuncMap) *Template { t.text.Funcs(template.FuncMap(funcMap)) return t } type FuncMap map[string]interface{}
在模板中使用自定义函数时,要用到管道的方法
{{ a | b }} 这种写法的意思是将 a 的输出通过管道再作为 b 的输入,最后呈现出来的是 b 的输出
例子:
{{ define "test" }} <!DOCTYPE html> <html lang="zh-CN"> <head> <title>自定义函数</title> </head> <body> {{/* {{ a | b }} 这种写法的意思是将 a 的输出通过管道再作为 b 的输入,最后呈现出来的是 b 的输出 */}} {{ . | scold }} </body> </html> {{end}}
package main import ( "fmt" "html/template" "net/http" ) func sayHello(w http.ResponseWriter,r *http.Request) { scold := func(a string) string { return a + "TNND" } t, err := template.New("test").Funcs(template.FuncMap{"scold" : scold}).ParseFiles("./test.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } err = t.Execute(w, "为什么不喝,") if err != nil { fmt.Printf("execute file failed err := %v",err) } } func main() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("listen address failed err = %v",err) } }
嵌套
就是在一个模板中嵌套另外的一个模板。
需要使用的语法为
在需要嵌套的地方 {{ template 模板名 . }} 其中,这个 . 是在模板中传递数据用的
例子:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>嵌套</title> </head> <body> ul :<br> {{ template "ul.tmpl" . }} <hr> ol :<br> {{ template "ol.tmpl" . }} </body> </html>
<ol> <li>{{ .name }}</li> <li>{{ .sex }}</li> </ol>
<ul> <li>{{ .name }}</li> <li>{{ .sex }}</li> </ul>
package main import ( "fmt" "html/template" "net/http" ) func nest(w http.ResponseWriter,r *http.Request) { // 不能写成template.ParseFiles("./ul.tmpl","./test.tmpl","./ol.tmpl") // 因为是test.tmpl是主模板,ul.tmpl和ol.tmpl需要等主模板解析完之后在解析 t, err := template.ParseFiles("./test.tmpl","./ul.tmpl","./ol.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } mp := map[string]interface{}{ "name": "张大炮", "sex": "女", } err = t.Execute(w, mp) if err != nil { fmt.Printf("execute file failed err := %v",err) } } func main() { http.HandleFunc("/",nest) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("listen address failed err = %v",err) } }
填空 block
相当于继承,一个网页项目会有一些公共的页面信息,为了不每个页面都将这些信息写上一边,就要有根模板,这时候其他的页面就需要继承根模板。
使用block
将数据传递给该模板名的模板 {{ block 模板名 数据}} {{ end }}
在使用时一定要引入根模板
用 . 来接受根模板传来的所有数据 {{ template 跟模板名 .}}
例子:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>填空</title> </head> <body> <div> <p style="text-align: center"> {{ block "content" .}} {{ end }} </p> </div> </body> </html>
{{ template "test.tmpl" .}} {{/* 一个项目里面肯定要有好些个功能,如果每一个功能都有一些相同作用的文件, 这样就很难保证这些文件不会出现重复的问题, 有两个解决方案, 1. 在每一个模板上方定义一个名字 2. 创建一个包,包里分层放,不同层代表着不同的功能 然后使用template.ParseGlob() 正则解析 */}} {{ define "content" }} {{ . }} {{end}}
package main import ( "fmt" "html/template" "net/http" ) func sayHello(w http.ResponseWriter,r *http.Request) { t, err := template.ParseFiles("./test.tmpl","./content.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } err = t.ExecuteTemplate(w,"content", "这都是大棚的瓜") if err != nil { fmt.Printf("execute file failed err := %v",err) } } func main() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("listen address failed err = %v",err) } }
安全测试
就像开头所说,html/template这个包传递给的模板的数据会进行安全处理。
测试:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>安全测试</title> </head> <body> {{/*并不会出现执行标签的现象*/}} 弹窗:{{ .msg }}<br> 链接1:{{ .a }}<br> 链接2:{{ .a | trust }}<br> </body> </html>
package main import ( "fmt" "html/template" "net/http" ) func sayHello(w http.ResponseWriter,r *http.Request) { t, err := template.New("test.tmpl").Funcs(template.FuncMap{ "trust": func(s string) template.HTML { return template.HTML(s) }, }).ParseFiles("./test.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } m := map[string]interface{}{ "msg":"<script>alert('张三撺掇着李四去王五家打了赵六')</script>", "a": "<a href='https://blog.csdn.net/weixin_52025712'>本人博客</a>", } err = t.Execute(w, m) if err != nil { fmt.Printf("execute file failed err := %v",err) } } func main() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("listen address failed err = %v",err) } }
修改默认标识符
模板中默认标识符 {{ }}
可能会与其他语言中的表示符冲突,这时候我们就要重新定义默认标识符,需要使用Delims
方法
// 修改默认标识符为 [ ] t, err := template.New("test.tmpl").Delims("[","]").ParseFiles("./test.tmpl")
Delims:
// left和rigth分别代表标识符左右两个部分 func (t *Template) Delims(left, right string) *Template { t.text.Delims(left, right) return t }
例子:
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>修改默认标识符</title> </head> <body> [ . ] </body> </html>
package main import ( "fmt" "html/template" "net/http" ) func sayHello(w http.ResponseWriter,r *http.Request) { t, err := template.New("test.tmpl").Delims("[","]").ParseFiles("./test.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } err = t.Execute(w, "hello") if err != nil { fmt.Printf("execute file failed err := %v",err) } } func main() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("listen address failed err = %v",err) } }
一个简单的表单传值的例子
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>表单传值</title> </head> <body> <form action="/" method="post"> <label> <input type="text" name="name"> </label><br> <label> <input type="text" name="age"> </label><br> <label> <input type="radio" name="sex" value="男"> </label> 男<br> <label> <input type="radio" name="sex" value="女"> </label> 女<br> <button type="submit">提交</button> </form> </body> </html>
<!DOCTYPE html> <html lang="zh-CN"> <head> <title>接受表单传过来的值</title> </head> <body> 姓名:{{ .name }}<br> 性别:{{ .sex }}<br> 年龄:{{ .age }} </body> </html>
package main import ( "fmt" "html/template" "net/http" ) func form(w http.ResponseWriter,r *http.Request) { switch r.Method { case "GET": t, err := template.ParseFiles("./get.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } err = t.Execute(w, nil) if err != nil { fmt.Printf("execute file failed err := %v",err) } case "POST": t, err := template.ParseFiles("./post.tmpl") if err != nil { fmt.Printf("parse file failed err := %v",err) } name := r.FormValue("name") //fmt.Printf("name = %s\n",name) sex := r.FormValue("sex") //fmt.Printf("sex = %s\n",sex) age := r.FormValue("age") //fmt.Printf("age = %s\n",age) m := map[string]interface{}{ "name":name, "sex":sex, "age":age, } err = t.Execute(w, m) if err != nil { fmt.Printf("execute file failed err := %v",err) } } } func main() { // 配置路由 http.HandleFunc("/",form) // 启动 err := http.ListenAndServe(":9000", nil) if err != nil { fmt.Printf("listen address failed err = %v",err) } }
参考文章:
希望大家能多去支持一下上面的两位大佬
最后再向大家推荐一首今天在单曲循环的歌遇见 西安话版 吴昊晨