1.自定义函数
Go的模板支持自定义函数
func tmpFuc(w http.ResponseWriter, r *http.Request) { // 自定义一个函数kua,第二个返回值必须是error类型 kua := func(name string) (string, error) { return name + "very nice!", nil } // 解析模板 // 当前路径下的tmpl // 创建一个模板对象 t := template.New("tem.tmpl") // 告诉模板引擎,现在多了一个自定义函数kua t.Funcs(template.FuncMap{ "kua": kua, }) // 进行解析 _, err := t.ParseFiles("./tem.tmpl") if err != nil { fmt.Println("ParseFiles failed error:%v", err) return } // 渲染模板 name := "dahe" err = t.Execute(w, name) if err != nil { fmt.Println("tmpl Execute failed err=%v", err) } }
模板使用自定义函数:
{{kua .}} ------------------------------- 输出:dahevery nice!
2.嵌套模板
我们可以在template中嵌套其他的template。这个template可以是单独的文件,也可以是通过define定义的template。
func tmpFuc(w http.ResponseWriter, r *http.Request) { // 解析模板,主模板在前,包含模板在后 t, err := template.ParseFiles("./tem.tmpl", "./ul.tmpl") if err != nil { fmt.Println("parse template failed , err=%v", err) return } name := "dahe" // 渲染模板 t.Execute(w, name) }
主模板:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>hint</title> </head> <body> {{template "ol.tmpl"}} {{template "ul.tmpl"}} <p>你好啊,{{.}}</p> {{/* 通过define自定义一个模板 */}} {{define "ol.tmpl"}} <ol> <li>java</li> <li>c++</li> <li>go</li> </ol> {{end}} </body> </html>
外部嵌套的ul.tmpl:
<ul> <li>注释</li> <li>日志</li> <li>测试</li> </ul>
浏览器输出如下:
3.block
block是定义模板{{define "name"}} T1 {{end}}和执行{{template "name" pipeline}}缩写,典型的用法是定义一组根模板,然后通过在其中重新定义块模板进行自定义。
模板页面:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>block</title> </head> <body> <h1>欢迎来到迷你抖音哦</h1> <p>{{block "content" .}}{{end}}</p> </body> </html>
继承A:
{{/*继承根模板*/}} {{template "base.tmpl" .}} {{/*重新定义块模板*/}} {{define "content"}} <p>这是home页面</p> <p>{{.}}</p> {{end}}
继承B:
{{/*继承根模板*/}} {{template "base.tmpl" .}} {{/*重新定义块模板*/}} {{define "content"}} <p>这是index页面</p> <p>{{.}}</p> {{end}}
浏览器输出:
4.修改默认的标识符
Go标准库的模板引擎使用的花括号{{和}}作为标识,而许多前端框架(如Vue和 AngularJS)也使用{{和}}作为标识符,所以当我们同时使用Go语言模板引擎和以上前端框架时就会出现冲突,这个时候我们需要修改标识符,修改前端的或者修改Go语言的。这里演示如何修改Go语言模板引擎默认的标识符:
template.New("test").Delims("{[", "]}").ParseFiles("./t.tmpl")
例子:后端
func index(w http.ResponseWriter, r *http.Request) { t, err := template.New("./templates/hint.tmpl"). Delims("{[", "]}"). ParseFiles("./templates/hint.tmpl") if err != nil { fmt.Println("parse template failed , err = %v", err) return } msg := "imustctf" t.ExecuteTemplate(w, "hint.tmpl", msg) }
模板文件:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>修改模板的默认标识符</title> </head> <body> <h1>欢迎来到迷你抖音哦</h1> <p>{[.]}</p> </body> </html>
5.text/template与html/tempalte的区别
html/template针对的是需要返回HTML内容的场景,在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击。
传入一段JS代码并使用html/template去渲染该文件,会在页面上显示出转义后的JS内容。不会出现弹窗, <script>alert('嘿嘿嘿')</script>。 这就是html/template为我们做的事。
但是在某些场景下,我们如果相信用户输入的内容,不想转义的话,可以自行编写一个safe函数,手动返回一个template.HTML类型的内容。示例如下:
func xss(w http.ResponseWriter, r *http.Request){ tmpl,err := template.New("xss.tmpl").Funcs(template.FuncMap{ "safe": func(s string)template.HTML { return template.HTML(s) }, }).ParseFiles("./xss.tmpl") if err != nil { fmt.Println("create template failed, err:", err) return } jsStr := `<script>alert('嘿嘿嘿')</script>` err = tmpl.Execute(w, jsStr) if err != nil { fmt.Println(err) } }
这样我们只需要在模板文件不需要转义的内容后面使用我们定义好的safe函数就可以了。
{{ . | safe }}