From f2b2821f0ce35b4b341e5c9f359cca414297832a Mon Sep 17 00:00:00 2001 From: vCaesar Date: Sun, 18 Dec 2016 16:05:32 +0800 Subject: [PATCH] Add 0.7.4.md syntax highlighting --- zh/07.4.md | 58 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/zh/07.4.md b/zh/07.4.md index f90fdb81..48db045a 100644 --- a/zh/07.4.md +++ b/zh/07.4.md @@ -12,6 +12,7 @@ Web应用反馈给客户端的信息中的大部分内容是静态的,不变 ## Go模板使用 在Go语言中,我们使用`template`包来进行模板处理,使用类似`Parse`、`ParseFile`、`Execute`等方法从文件或者字符串加载模板,然后执行类似上面图片展示的模板的merge操作。请看下面的例子: +```Go func handler(w http.ResponseWriter, r *http.Request) { t := template.New("some template") //创建一个模板 @@ -19,7 +20,7 @@ Web应用反馈给客户端的信息中的大部分内容是静态的,不变 user := GetUser() //获取当前用户信息 t.Execute(w, user) //执行模板的merger操作 } - +``` 通过上面的例子我们可以看到Go语言的模板操作非常的简单方便,和其他语言的模板处理类似,都是先获取数据,然后渲染数据。 为了演示和测试代码的方便,我们在接下来的例子中采用如下格式的代码 @@ -33,6 +34,7 @@ Web应用反馈给客户端的信息中的大部分内容是静态的,不变 ### 字段操作 Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{.}}`表示当前的对象,这和Java或者C++中的this类似,如果要访问当前对象的字段通过`{{.FieldName}}`,但是需要注意一点:这个字段必须是导出的(字段首字母必须是大写的),否则在渲染的时候就会报错,请看下面的这个例子: +```Go package main @@ -51,8 +53,9 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{ p := Person{UserName: "Astaxie"} t.Execute(os.Stdout, p) } - +``` 上面的代码我们可以正确的输出`hello Astaxie`,但是如果我们稍微修改一下代码,在模板中含有了未导出的字段,那么就会报错 +```Go type Person struct { UserName string @@ -60,7 +63,7 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{ } t, _ = t.Parse("hello {{.UserName}}! {{.email}}") - +``` 上面的代码就会报错,因为我们调用了一个未导出的字段,但是如果我们调用了一个不存在的字段是不会报错的,而是输出为空。 如果模板中输出`{{.}}`,这个一般应用于字符串对象,默认会调用fmt包输出字符串的内容。 @@ -72,6 +75,7 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{ - {{with}}操作是指当前对象的值,类似上下文的概念 详细的使用请看下面的例子: +```Go package main @@ -109,9 +113,10 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{ Friends: []*Friend{&f1, &f2}} t.Execute(os.Stdout, p) } - +``` ### 条件处理 在Go模板里面如果需要进行条件判断,那么我们可以使用和Go语言的`if-else`语法类似的方式来处理,如果pipeline为空,那么if就认为是false,下面的例子展示了如何使用`if-else`语法: +```Go package main @@ -133,44 +138,54 @@ Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{ tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if部分 {{else}} else部分.{{end}}\n")) tIfElse.Execute(os.Stdout, nil) } - +``` 通过上面的演示代码我们知道`if-else`语法相当的简单,在使用过程中很容易集成到我们的模板代码中。 > 注意:if里面无法使用条件判断,例如.Mail=="astaxie@gmail.com",这样的判断是不正确的,if里面只能是bool值 ### pipelines Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的语法你是不是经常使用,过滤当前目录下面的文件,显示含有"beego"的数据,表达的意思就是前面的输出可以当做后面的输入,最后显示我们想要的数据,而Go语言模板最强大的一点就是支持pipe数据,在Go语言里面任何`{{}}`里面的都是pipelines数据,例如我们上面输出的email里面如果还有一些可能引起XSS注入的,那么我们如何来进行转化呢? +```Go {{. | html}} - + +``` 在email输出的地方我们可以采用如上方式可以把输出全部转化html的实体,上面的这种方式和我们平常写Unix的方式是不是一模一样,操作起来相当的简便,调用其他的函数也是类似的方式。 ### 模板变量 有时候,我们在模板使用过程中需要定义一些局部变量,我们可以在一些操作中申明局部变量,例如`with``range``if`过程中申明局部变量,这个变量的作用域是`{{end}}`之前,Go语言通过申明的局部变量格式如下所示: +```Go $variable := pipeline - +``` 详细的例子看下面的: +```Go {{with $x := "output" | printf "%q"}}{{$x}}{{end}} {{with $x := "output"}}{{printf "%q" $x}}{{end}} {{with $x := "output"}}{{$x | printf "%q"}}{{end}} + +``` ### 模板函数 模板在输出对象的字段值时,采用了`fmt`包把对象转化成了字符串。但是有时候我们的需求可能不是这样的,例如有时候我们为了防止垃圾邮件发送者通过采集网页的方式来发送给我们的邮箱信息,我们希望把`@`替换成`at`例如:`astaxie at beego.me`,如果要实现这样的功能,我们就需要自定义函数来做这个功能。 每一个模板函数都有一个唯一值的名字,然后与一个Go函数关联,通过如下的方式来关联 +```Go type FuncMap map[string]interface{} - +``` 例如,如果我们想要的email函数的模板函数名是`emailDeal`,它关联的Go函数名称是`EmailDealWith`,那么我们可以通过下面的方式来注册这个函数 +```Go t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith}) - +``` `EmailDealWith`这个函数的参数和返回值定义如下: +```Go func EmailDealWith(args …interface{}) string - +``` 我们来看下面的实现例子: +```Go package main @@ -230,8 +245,9 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的 t.Execute(os.Stdout, p) } - +``` 上面演示了如何自定义函数,其实,在模板包内部已经有内置的实现函数,下面代码截取自模板包里面 +```Go var builtins = FuncMap{ "and": and, @@ -248,9 +264,10 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的 "urlquery": URLQueryEscaper, } - +``` ## Must操作 模板包里面有一个函数`Must`,它的作用是检测模板是否正确,例如大括号是否匹配,注释是否正确的关闭,变量是否正确的书写。接下来我们演示一个例子,用Must来判断模板是否正确: +```Go package main @@ -272,23 +289,29 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的 template.Must(tErr.Parse(" some static text {{ .Name }")) } +``` 将输出如下内容 +``` + The first one parsed OK. The second one parsed OK. The next one ought to fail. panic: template: check parse error with Must:1: unexpected "}" in command - +``` ## 嵌套模板 我们平常开发Web应用的时候,经常会遇到一些模板有些部分是固定不变的,然后可以抽取出来作为一个独立的部分,例如一个博客的头部和尾部是不变的,而唯一改变的是中间的内容部分。所以我们可以定义成`header`、`content`、`footer`三个部分。Go语言中通过如下的语法来申明 +```Go {{define "子模板名称"}}内容{{end}} - +``` 通过如下方式来调用: +```Go {{template "子模板名称"}} - +``` 接下来我们演示如何使用嵌套模板,我们定义三个文件,`header.tmpl`、`content.tmpl`、`footer.tmpl`文件,里面的内容如下 +```html //header.tmpl {{define "header"}} @@ -315,8 +338,9 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的 {{end}} - +``` 演示代码如下: +```Go package main @@ -336,7 +360,7 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的 fmt.Println() s1.Execute(os.Stdout, nil) } - +``` 通过上面的例子我们可以看到通过`template.ParseFiles`把所有的嵌套模板全部解析到模板里面,其实每一个定义的{{define}}都是一个独立的模板,他们相互独立,是并行存在的关系,内部其实存储的是类似map的一种关系(key是模板的名称,value是模板的内容),然后我们通过`ExecuteTemplate`来执行相应的子模板内容,我们可以看到header、footer都是相对独立的,都能输出内容,content 中因为嵌套了header和footer的内容,就会同时输出三个的内容。但是当我们执行`s1.Execute`,没有任何的输出,因为在默认的情况下没有默认的子模板,所以不会输出任何的东西。 >同一个集合类的模板是互相知晓的,如果同一模板被多个集合使用,则它需要在多个集合中分别解析