go模板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wyy626562203/article/details/83691806

go模板

介绍

template包用于生成文本输出的模板,要生成HTML输出,需要用到html/template,和text/template具有相同的接口,但会自动将输出转化为安全的HTML格式输出,可以抵抗一些网络攻击。模板标签用"{{“和”}}"括起来。

通过将数据结构作为模板的参数来生成文本。模板中通过引用数据结构的元素(通常是结构的字段或映射中的键)来控制执行过程和需要显示的值。模板执行时会遍历结构并将指针表示为’.’(称之为"dot")指向运行过程中数据结构的当前位置的值。

模板的输入文本格式必须是UTF-8编码。 “Action” - 数据运算或控制结构 - 由“{{”和“}}”分隔,在Action之外的所有文本都不做修改的拷贝到输出中。Action内部不能有换行,但注释可以有换行。

一旦解析,模板可以安全地并行执行,但是如果并行执行共享Writer,则输出可以是交错的。

这是一个简单的例子,打印出“17件由羊毛制成”。

type Inventory struct {
	Material string
	Count    uint
}
sweaters := Inventory{"wool", 17}

tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
if err != nil { 
    panic(err) 
}

err = tmpl.Execute(os.Stdout, sweaters)
if err != nil { 
    panic(err) 
}

空格

默认情况下,执行模板时,将逐字复制actions之间的所有文本。 例如,运行程序时,上例中的字符串" items are made of "出现在标准输出上。但是,为了帮助格式化模板源代码,如果操作的左分隔符(默认为“{{”)后面紧跟一个减号和ASCII空格字符(“{{-”),则所有尾随空格都会紧接在文本之前。 同样,如果右边分隔符(“}}”)前面有空格和减号(“-}}”),则去除文本中紧随其后的空格。在这些修剪标记中,必须存在ASCII空格字符; “{{-3}}”解析为数字-3

例如,模板

"{{23 }} < {{ 45}}"
"{{23 -}} < {{- 45}}"

输出

"23 < 45"
"23<45"

注释

{{/* a comment */}}

执行时会忽略。可以多行,注释不能嵌套,并且必须紧贴分界符始止,就像这里表示的一样。

package main

import (
	"html/template"
	"os"
)

func main()  {
	//创建一个模板
	t := template.New("test")
	//注释
	t, _ = t.Parse(`{{/*我是注释*/}}`)
	t.Execute(os.Stdout, nil)
}

输出

{{pipeline}}
pipeline的值的默认文本表示会被拷贝到输出里。

package main

import (
	"html/template"
	"os"
)

func main()  {
	//创建一个模板
	t := template.New("test")
	//显示的值
	d := "this is a"
	t, _ = t.Parse(`{{.}}{{" test!"}}`)
	t.Execute(os.Stdout, d)

	//output: this is a test!
}

变量

点号用于输出当前对象的值,$用于输出模板中定义变量的值。

Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下:

$variable := pipeline

其中$variable是变量的名字。声明变量的action不会产生任何输出。

赋值先前声明的变量,语法如下:

$variable = pipeline

如果"range" action初始化了1个变量,该变量设置为迭代器的每一个成员元素,如果初始化了逗号分隔的2个变量:

range $index, $element := pipeline

这时, i n d e x index和 element分别设置为数组/切片的索引或者字典的键,以及对应的成员元素。注意这和go range从句只有一个参数时设置为索引/键不同!

一个变量的作用域只到声明它的控制结构(“if”、“with”、“range”)的"end"为止,如果不是在控制结构里声明会直到模板结束为止。子模板的调用不会从调用它的位置(作用域)继承变量。

模板开始执行时,$会设置为传递给Execute方法的参数,就是说,dot的初始值。

package main

import (
	"os"
	"text/template"
)
type User struct {
	Id       string
	UserName string
	Age      int
	Ct       Contact
}

type Contact struct {
	Name string
	Tel  int
}

func main()  {
	//模板函数
	t := template.New("test1")
	t, _ = t.Parse(`
			{{.Id}} {{.UserName}} {{.Age}} {{.Ct.Tel}}
			{{$a := .Ct}} {{$a.tel}}
                     `)
	t.Execute(os.Stdout, User{"1234", "wyy", 22,Contact{"mama",195566985}})

	//output:
	//1234 wyy 22 195566985
}

变量的引用

{{.}}

此标签输出当前对象的值

{{.Admpub}}

表示输出Struct对象中字段或方法名称为“Admpub”的值。

当“Admpub”是匿名字段时,可以访问其内部字段或方法,比如“Com”:{{.Admpub.Com}} ,

如果“Com”是一个方法并返回一个Struct对象,同样也可以访问其字段或方法:{{.Admpub.Com.Field1}}

{{.Method1 "parm1" "parm2"}}
调用方法“Method1”,将后面的参数值依次传递给此方法,并输出其返回值。

{{$admpub}}
此标签用于输出在模板中定义的名称为“admpub”的变量。当KaTeX parse error: Expected '}', got 'EOF' at end of input: …ct对象时,可访问其字段:{{admpub.Field1}}

Arguments表示一个简单的值,由下面的某一条表示的值。

  • go语法的布尔值、字符串、字符、整数、浮点数、虚数、复数,视为无类型字面常数,字符串不能跨行
  • 关键字nil,代表一个go的无类型的nil值
  • 字符’.’(句点,用时不加单引号),代表dot的值
  • 变量名,以美元符号起始加上(可为空的)字母和数字构成的字符串,如:$piOver2和$;
    执行结果为变量的值,变量参见下面的介绍
  • 结构体数据的字段名,以句点起始,如:.Field;
    执行结果为字段的值,支持链式调用:.Field1.Field2;
    字段也可以在变量上使用(包括链式调用):$x.Field1.Field2;
  • 字典类型数据的键名;以句点起始,如:.Key;
    执行结果是该键在字典中对应的成员元素的值;
    键也可以和字段配合做链式调用,深度不限:.Field1.Key1.Field2.Key2;
    虽然键也必须是字母和数字构成的标识字符串,但不需要以大写字母起始;
    键也可以用于变量(包括链式调用):$x.key1.key2;
  • 数据的无参数方法名,以句点为起始,如:.Method;
    执行结果为dot调用该方法的返回值,dot.Method();
    该方法必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
    如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;
    方法可和字段、键配合做链式调用,深度不限:.Field1.Key1.Method1.Field2.Key2.Method2;
    方法也可以在变量上使用(包括链式调用):$x.Method1.Field;
  • 无参数的函数名,如:fun;
    执行结果是调用该函数的返回值fun();对返回值的要求和方法一样;函数和函数名细节参见后面。
  • 上面某一条的实例加上括弧(用于分组)
    执行结果可以访问其字段或者键对应的值:
    print (.F1 arg1) (.F2 arg2)
    (.StructValuedMethod “arg”).Field

Arguments可以是任何类型:如果是指针,在必要时会自动表示为指针指向的值;如果执行结果生成了一个函数类型的值,如结构体的函数类型字段(返回一个函数指针),该函数不会自动调用,但可以在if等action里视为真。如果要调用它,使用call函数,参见下面。

package main

import (
	"os"
	"text/template"
)
type User struct {
	Id       string
	UserName string
	Age      int
}

func main()  {
	//模板函数
	t := template.New("test1")
	t, _ = t.Parse(`
		{{.Id}} {{.UserName}} {{.Age}}
                `)
	t.Execute(os.Stdout, User{"1234", "wyy", 22})

	//output:
	//1234 wyy 22
}

管道

Pipeline是一个(可能是链状的)command序列。Command可以是一个简单值(argument)或者对函数或者方法的(可以有多个参数的)调用:

Argument
    执行结果是argument的执行结果
.Method [Argument...]
    方法可以独立调用或者位于链式调用的末端,不同于链式调用中间的方法,可以使用参数;
    执行结果是使用给出的参数调用该方法的返回值:dot.Method(Argument1, etc.);
functionName [Argument...]
    执行结果是使用给定的参数调用函数名指定的函数的返回值:function(Argument1, etc.)

pipeline通常是将一个command序列分割开,再使用管道符’|'连接起来(但不使用管道符的command序列也可以视为一个管道)。在一个链式的pipeline里,每个command的结果都作为下一个command的最后一个参数。pipeline最后一个command的输出作为整个管道执行的结果。

command的输出可以是1到2个值,如果是2个后一个必须是error接口类型。如果error类型返回值非nil,模板执行会中止并将该错误返回给执行模板的调用者。

{{FuncName1}}
此标签将调用名称为“FuncName1”的模板函数(等同于执行“FuncName1()”,不传递任何参数)并输出其返回值。

{{FuncName1 "parm1" "parm2"}}
此标签将调用“FuncName1(“参数值1”, “参数值2”)”,并输出其返回值

{{.Admpub|FuncName1}}
此标签将调用名称为“FuncName1”的模板函数(等同于执行“FuncName1(this.Admpub)”,将竖线“|”左边的“.Admpub”变量值作为函数参数传送)并输出其返回值。

package main

import (
	"os"
	"text/template"
)
type User struct {
	Id       string
	UserName string
	Age      int
}

//记得函数名首字母大写
func (u User)Test(msg string) string {
	return msg
}

//这个函数是注册到模板,可以不用大写
func test1(msg string) string {
	return msg + " ==>"
}

func main()  {
	//模板函数
	t1 := template.New("test1")
	//注册模板函数
	t1.Funcs(template.FuncMap{"test1": test1})
	// {{函数名}}输出函数返回值
	// {{函数名 参数1 参数2}}
	// {{.字段名|函数名}} 以字段的值作为函数的参数
	t1, _ = t1.Parse(`
                      {{.UserName|test1}}
		      {{ "2018-01-02 15:04:05" | .Test}}
                     `)
	t1.Execute(os.Stdout, User{"1234", "wyy", 22})

	//output:
	//wyy ==>
	//2018-01-02 15:04:05
}

条件

如果pipeline的值为empty,不产生输出,否则输出T1执行结果。不改变dot的值。Empty值包括false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典、字符串。

{{if pipeline}} T1 {{end}}

如果pipeline的值为empty,输出T0执行结果,否则输出T1执行结果。不改变dot的值。

{{if pipeline}} T1 {{else}} T0 {{end}}

用于简化if-else,else action可以直接包含另一个if

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

等价于:

{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
package main

import (
	"html/template"
	"os"
)

func comp(a int) bool {
	if a == 3 {
		return true
	}
	return false
}

func main()  {
	t := template.New("test")
	t.Funcs(template.FuncMap{"comp": comp})

	t, _ = t.Parse(`{{if 1}}
                          	true
                         {{else}}
				false
                      	 {{end}}

                         {{$a := 4}}
                         {{if $a|comp}}
                             $a=3
                         {{else}}
                             $a!=3
                         {{end}}`)
	t.Execute(os.Stdout, nil)

	//output: true
	//        $a!=3
}

遍历

pipeline的值必须是数组、切片、字典或者通道。如果pipeline的值其长度为0,不会有任何输出;否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1;如果pipeline的值为字典,且键可排序的基本类型,元素也会按键的顺序排序。

{{range pipeline}} T1 {{end}}

pipeline的值必须是数组、切片、字典或者通道。如果pipeline的值其长度为0,不改变dot的值并执行T0;否则会修改dot并执行T1。

{{range pipeline}} T1 {{else}} T0 {{end}}
package main

import (
	"text/template"
	"os"
)
type User struct {
	Contact  map[string]string
	Num      int
}

func main()  {
	t := template.New("test")
	t, _ = t.Parse(`
                        {{range $k, $v := .Contact}}
                        {{$k}} {{$v}}
                     	{{end}}

			{{range .Contact}}
    			{{.}}
			{{end}}

			{{range .Contact}}
			{{else}}
			{{/* 当 .Pages 为空 或者 长度为 0 时会执行这里 */}}
			{{end}}
                       `)
	info := make(map[string]string)
	info["qq"] = "656965586"
	info["tel"] = "15399265339"
	t.Execute(os.Stdout, User{info,100})

	//output:
	//qq  656965586
	//tel 15399265339

	//656965586
	//15399265339
}

定义局部变量

with 用于重定向 pipeline,创建一个封闭的作用域,在其范围内,可以使用.action,而与外面的.无关,只与with的参数有关。如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。

{{with pipeline}} T1 {{end}}

如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。

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

import (
	"text/template"
	"os"
)
type User struct {
	Contact  map[string]string
	Num      int
}

func main()  {
	t := template.New("test")
	t, _ = t.Parse(`
			{{with "hello"}}{{printf "%q" .}}{{end}}

            		{{with .Contact}}
                        {{range $k, $v := .}}
			{{$k}} {{$v}}
                        {{end}}
                      	{{end}}
                       `)
	info := make(map[string]string)
	info["qq"] = "656965586"
	info["tel"] = "15399265339"
	t.Execute(os.Stdout, User{info,100})

	//output:
	//"hello"
	//qq 656965586
	//tel 15399265339
}

嵌入子模板

每一个模板在创建时都要用一个字符串命名。同时,每一个模板都会和0或多个模板关联,并可以使用它们的名字调用这些模板;这种关联可以传递,并形成一个模板的名字空间。

一个模板可以通过模板调用实例化另一个模板;参见上面的"template" action。name必须是包含模板调用的模板相关联的模板的名字。

执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为""。

嵌入名称为“name”的子模板。使用前,请确保已经用“{{define “name”}}子模板内容{{end}}”定义好了子模板内容。

{{template "name"}}

执行名为name的模板,提供给模板的参数为pipeline的值。将管道的值赋给子模板中的“.”(即“{{.}}”)

{{template "name" pipeline}}

典型用法是定义一组根模板,然后通过重新定义其中的block模板进行自定义。

{{block "name" pipeline}} T1 {{end}}

等价于

{{define "name"}} T1 {{end}}
{{template "name" pipeline}}

当解析模板时,可以定义另一个模板,该模板会和当前解析的模板相关联。模板必须定义在当前模板的最顶层,就像go程序里的全局变量一样。

这种定义模板的语法是将每一个子模板的声明放在"define"和"end" action内部。

define action使用给出的字符串常数给模板命名,举例如下:

`{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}`

它定义了两个模板T1和T2,第三个模板T3在执行时调用这两个模板;最后该模板调用了T3。输出结果是:

ONE TWO

采用这种方法,一个模板只能从属于一个关联。如果需要让一个模板可以被多个关联查找到;模板定义必须多次解析以创建不同的*Template 值,或者必须使用Clone或AddParseTree方法进行拷贝。

可能需要多次调用Parse函数以集合多个相关的模板;参见ParseFiles和ParseGlob函数和方法,它们提供了简便的途径去解析保存在文件中的存在关联的模板。

一个模板可以直接调用或者通过ExecuteTemplate方法调用指定名字的相关联的模板;我们可以这样调用模板:

err := tmpl.Execute(os.Stdout, "no data needed")
if err != nil {
	log.Fatalf("execution failed: %s", err)
}

或显式的指定模板的名字来调用:

err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
if err != nil {
	log.Fatalf("execution failed: %s", err)
}
package main

import (
	"os"
	"text/template"
)
type User struct {
	Id       string
	UserName string
	Age      int
}

func test() string {
	return "test"
}

func main()  {
	//嵌套模板
	t := template.New("test");
	t.Funcs(template.FuncMap{"test": test});
	// {{define "模板名"}}模板内容{{end}} 定义模板
	// {{template "模板名"}} 引入模板
	// {{template "模板名" 函数}} 将函数中的值赋给模板中的{{.}}
	t, _ = t.Parse(`
		  {{/*下面三句模板定义不会有输出*/}}
                  {{define "tp1"}} 我是模板1 {{end}}
                  {{define "tp2"}} 我是模板2 {{.}} {{end}}
                  {{define "tp3"}} {{- template "tp1"}} {{template "tp2"}} {{end}}
                      
  		  {{/*下面三句会有输出*/}}
		  {{template "tp1"}}
                  {{template "tp2" test}}
                  {{template "tp3" test}}
                     `);
	t.Execute(os.Stdout, nil);
	//output:
	//我是模板1
	//我是模板2 test
	//我是模板1   我是模板2 <no value>
}

预定义的模板全局函数

执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。

预定义的全局函数如下:

and
    函数返回它的第一个empty参数或者最后一个参数;
    就是说"and x y"等价于"if x then y else x";所有参数都会执行;
call
    执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
    如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
    其中Y是函数类型的字段或者字典的值,或者其他类似情况;
    call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
    该函数类型值必须有12个返回值,如果有2个则后一个必须是error接口类型;
    如果有2个返回值的方法返回的errornil,模板执行会中断并返回给调用模板执行者该错误;
html
    转义文本中的html标签,如将"<"转义为"&lt;"">"转义为"&gt;"等。
index
    执行结果为第一个参数以剩下的参数为索引/键指向的值;
    如"index x 1 2 3"返回x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
js
    返回用JavaScript的escape处理后的文本。
len
    返回它的参数的整数类型长度
not
    返回它的单个参数的布尔值的否定
or
    返回第一个非empty参数或者最后一个参数;
    亦即"or x y"等价于"if x then x else y";所有参数都会执行;
print
    即fmt.Sprint
printf
    即fmt.Sprintf
println
    即fmt.Sprintln
urlquery
    返回适合在URL查询中嵌入到形参中的文本转义值。(类似于PHP的urlencode)


布尔函数会将任何类型的零值视为假,其余视为真。

下面是定义为函数的二元比较运算的集合:

eq      如果arg1 == arg2则返回真
ne      如果arg1 != arg2则返回真
lt      如果arg1 < arg2则返回真
le      如果arg1 <= arg2则返回真
gt      如果arg1 > arg2则返回真
ge      如果arg1 >= arg2则返回真

为了简化多参数相等检测,eq(只有eq)可以接受2个或更多个参数,和go的||不一样,不做惰性运算,所有参数都会执行,它会将第一个参数和其余参数依次比较,

{{eq arg1 arg2 arg3 arg4}}

即只能作如下比较:

arg1==arg2 || arg1==arg3 || arg1==arg4 ...

比较函数只适用于基本类型(或重定义的基本类型,如"type Celsius float32")。它们实现了go语言规则的值的比较,但具体的类型和大小会忽略掉,因此任意类型有符号整数值都可以互相比较;任意类型无符号整数值都可以互相比较;等等。但是,整数和浮点数不能互相比较。


package main

import (
	"text/template"
	"os"
)
type User struct {
	Contact  map[string]string
}

func sum() func(nums ...int) (int, error) {
	return func(nums ...int) (int, error) {
		sum := 0
		for _, v := range nums {
			sum += v
		}
		return sum, nil
	};
}

func main()  {
	//内置的模板函数
	t := template.New("test")
	t.Funcs(template.FuncMap{"sum": sum})
	t, _ = t.Parse(`
                        //如果3为真,返回4,否则返回3
                        {{and 3 4}}
 
                        //call后第一个参数的返回值必须是一个函数
                        {{call sum 1 3 5 7}}
 
                        //转义文本中的html标签
                        {{"<br>"|html}}
 
                        //返回Contact索引为qq的值
                        {{index .Contact "qq"}}
 
                        //返回用js的escape处理后的文本
                        {{"?a=123&b=你好"|js}}
 
                        //返回参数的长度值
                        {{"hello"|len}}
 
                        //返回单一参数的布尔否定值
                        {{not 0}}
 
                        //如果3为真,返回3,否则返回4
                        {{or 3 4}}
 
                        //fmt.Sprint的别名
                        {{"你好"|print "世界"}}
 
                        //fmt.Sprintf的别名
                        {{"你好"|printf "%d %s" 123}}
 
                        //fmt.Sprintln的别名
                        {{"你好"|println "世界"}}
 
                        //url中get参数转义
                        {{"?q=关键字&p=1"|urlquery}}
 
                        //等于
                        {{if eq 1 1}}1=1{{end}}
 
                        //不等于
                        {{if ne 1 2}}1!=1{{end}}
 
                        //小于
                        {{if lt 1 3}}1<3{{end}}
 
                        //小于等于
                        {{if le 3 3}}3<=3{{end}}
 
                        //大于
                        {{if gt 3 1}}3>1{{end}}
 
                        //大于等于
                        {{if ge 3 3}}3>=3{{end}}
                       `)
	info := make(map[string]string)
	info["qq"] = "656965586"
	info["tel"] = "15399265339"
	t.Execute(os.Stdout, User{info})

	//output:
	//如果3为真,返回4,否则返回3
	//4

	//call后第一个参数的返回值必须是一个函数
	//16

	//转义文本中的html标签
	//&lt;br&gt;

	//返回Contact索引为qq的值
	//656965586

	//回用js的escape处理后的文本
	//?a=123&amp;b=你好

	//返回参数的长度值
	//5

	//返回单一参数的布尔否定值
	//true

	//如果3为真,返回3,否则返回4
	//3

	//fmt.Sprint的别名
	//世界你好

	//fmt.Sprintf的别名
	//123 你好

	//fmt.Sprintln的别名
	//世界 你好


	//url中get参数转义
	//%3Fq%3D%E5%85%B3%E9%94%AE%E5%AD%97%26p%3D1

	//等于
	//1=1

	//不等于
	//1!=1
    
	//小于
	//1<3
    
	//小于等于
	//3<=3

	//大于
	//3>1

	//大于等于
	//3>=3
}

自定义模板函数

package main

import (
	"os"
	"text/template"
)
type User struct {
	Id       string
	UserName string
	Age      int
}

func (u User)Test(msg string) string {
	return msg
}

func test1() string {
	return "test1"
}

func test2(msg string) string {
	return msg + " ==>"
}

func main()  {
	//模板函数
	t1 := template.New("test1")
	//注册模板函数
	t1.Funcs(template.FuncMap{"test1": test1})
	t1.Funcs(template.FuncMap{"test2": test2})
	// {{函数名}}输出函数返回值
	// {{函数名 参数1 参数2}}
	// {{.字段名|函数名}} 以字段的值作为函数的参数
	t1, _ = t1.Parse(`
                      {{test1}}
                      {{test2 "test2"}}
		      {{.Test "2016-01-02 15:04:05"}}
                     `)
	t1.Execute(os.Stdout, User{"1234", "wyy", 22})

	//output:
	//test1
	//test2 ==>
	//2016-01-02 15:04:05
}

例子

下面是一些单行模板,展示了pipeline和变量。所有都生成加引号的单词"output":

{{"\"output\""}}
	字符串常量
{{`"output"`}}
	原始字符串常量
{{printf "%q" "output"}}
	函数调用
{{"output" | printf "%q"}}
	函数调用,最后一个参数来自前一个command的返回值
{{printf "%q" (print "out" "put")}}
	括号内的参数
{{"put" | printf "%s%s" "out" | printf "%q"}}
	玩出花的管道的链式调用
{{"output" | printf "%s" | printf "%q"}}
	管道的链式调用
{{with "output"}}{{printf "%q" .}}{{end}}
	使用dot的with action
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
	创建并使用变量的with action
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
	将变量使用在另一个action的with action
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
	以管道形式将变量使用在另一个action的with action  

内容转义

在以下情况,模板标签输出的内容会被转义:

  • 在HTML代码里输出HTML代码时,HTML代码会被转义;
  • 在Javascript代码里输出Javascript代码时,Javascript代码会被转义;
  • 在CSS代码里输出CSS代码时,CSS代码会被转义

有时候,我们并不需要golang的模板引擎在这些地方进行转义,这时候应该怎么办呢?
我们只需要将要输出的内容转为相应的template.HTML、template.JS、template.CSS数据类型就可以避免转义了。这里的template是指html/template包。

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/83691806