作者:人世间
链接:https://www.jianshu.com/p/05671bab2357
來源:简书
共12312字,阅读需31分钟
前后端分离的Restful架构大行其道,传统的模板技术已经不多见了。实际上只是渲染的地方由后端转移到了前端,模板的渲染技术本质上还是一样的。简而言之就是字串模板和数据的结合。
golang提供了两个标准库用来处理模板和。我们使用格式化html字符。
模板引擎
模板引擎很多,Python的jinja,nodejs的jade等都很好。所谓模板引擎,则将模板和数据进行渲染的输出格式化后的字符程序。对于go,执行这个流程大概需要三步。
1、创建模板对象
2、加载模板字串
3、执行渲染模板
其中最后一步就是把加载的字符和数据进行格式化。其过程可以总结下图:
warming up
go提供的标准库提供了很多处理模板的接口。我们的项目结构为:
templates文件夹有两个文件,分别为模板文件。 文件如下:
我们可以使用ParseFiles方法加载模板,该方法会返回一个模板对象和错误,接下来就可以使用模板对象执行模板,注入数据对象。go的提供了一些模板标签,称之为action,也是一种action,更多的action稍后解释。
我们打印了t模板对象的Name方法,实际上,每一个模板,都有一个名字,如果不显示指定这个名字,go将会把文件名(包括扩展名当成名字)本例则是。访问之后可以看见返回的html字串:
go不仅可以解析模板文件,也可以直接解析模板字串,这就是标准的处理,新建-加载-执行三部曲:
实际开发中,最终的页面很可能是多个模板文件的嵌套结果。go的ParseFiles也支持加载多个模板文件,不过模板对象的名字则是第一个模板文件的文件名。
可见打印的还是 layout.html的名字,执行的模板的时候,并没有index.html的模板内容。
此外,还有ParseGlob方法,可以通过glob通配符加载模板。
模板命名与嵌套
模板命名
前文已经提及,模板对象是有名字的,可以在创建模板对象的时候显示命名,也可以让go自动命名。可是涉及到嵌套模板的时候,该如何命名模板呢,毕竟模板文件有好几个?
go提供了方法,用于执行指定名字的模板。例如加载layout.html模板的时候,可以指定layout.html
似乎和Execute方法没有太大的差别。下面修改一下layout.html文件:
在模板文件中,使用了这个action给模板文件命名了。虽然我们ParseFiles方法返回的模板对象t的名字还是, 但是ExecuteTemplate执行的模板却是html文件中定义的。
不仅可以通过define定义模板,还可以通过template action引入模板,类似jinja的include特性。修改 layout.html 和 index.html
index.html
go的代码也需要修改,使用ParseFiles加载需要渲染的模板文件:
访问可以看到 index被layout模板include了:
单文件嵌套
总而言之,创建模板对象后和加载多个模板文件,执行模板文件的时候需要指定base模板(layout),在base模板中可以include其他命名的模板。无论点,define,template这些花括号包裹的东西都是go的action(模板标签)
Action
action是go模板中用于动态执行一些逻辑和展示数据的形式。大致分为下面几种:
1、条件语句
2、迭代
3、封装
4、引用
我们已经见识了template引用的用法,下面么再看看其他的用法
条件判断
条件判断的语法很简单:
arg 可以是基本数据结构,也可以是表达式:if-end包裹的内容为条件为真的时候展示。与if语句一样,模板也可以有else语句。
此时就能看见,当的值为true的时候显示if的逻辑,否则显示else的逻辑。
迭代
对于一些数组,切片或者是map,可以使用迭代的action,与go的迭代类似,使用range进行处理:
可以看见输出了一堆li列表。迭代的时候,还可以使用设置循环变量:
可以看见和迭代切片很像。rang也可以使用else语句:
当range的结构为空的时候,则会执行else分支的逻辑。
with封装
with语言在Python中可以开启一个上下文环境。对于go模板,with语句类似,其含义就是创建一个封闭的作用域,在其范围内,可以使用.action,而与外面的.无关,只与with的参数有关:
访问结果如下:
可见 with语句的与其外面的是两个不相关的对象。with语句也可以有else。else中的则和with外面的一样,毕竟只有with语句内才有封闭的上下文:
访问效果为:
引用
我们已经介绍了模板嵌套引用的技巧。引用除了模板的include,还包括参数的传递。
修改 layout.html, layout中引用了 index模板:
index.html模板的内容也打印了 :
访问的效果如下,index.html 中的点并没有数据。
我们可以修改引用语句,把参数传给子模板,再次访问,就能看见index.html模板也有数据啦。
参数,变量和管道
模板的参数可以是go中的基本数据类型,如字串,数字,布尔值,数组切片或者一个结构体。在模板中设置变量可以使用 。我们在range迭代的过程使用了设置变量的方式。
go还有一个特性就是模板的管道函数,熟悉django和jinja的开发者应该很熟悉这种手法。通过定义函数过滤器,实现模板的一些简单格式化处理。并且通过管道哲学,这样的处理方式可以连成一起。
例如 模板内置了一些函数,比如格式化输出:
函数
既然管道符可以成为模板中的过滤器,那么除了内建的函数,能够自定义函数可以扩展模板的功能。幸好go的模板提供了自定义模板函数的功能。
想要创建一个定义函数只需要两步:
1、创建一个类型的map,key是模板函数的名字,value是其函数的定义。
2、将 注入到模板中。
然后在模板中使用,当然也可以不适用管道过滤器,而是使用正常的函数调用形式,。
注意,函数的注入,必须要在parseFiles之前,因为解析模板的时候,需要先把函数编译注入。
智能上下文
上面所介绍的特性,基本上是大多数模板引擎都具有的功能。go还提供了一个更有意思的特性。那就是根据上下文显示模板的内容。例如字符的转义,会根据所显示的上下文环境而智能变化。比如同样的html标签,在Js和html环境中,其转义的内容是不一样的:
模板文件:
访问结果
可以看见go会自动为我们处理html标签的转义。这对web安全具有重要作用。避免了一些XSS攻击。
XSS安全
安全是一个很大的话题,XSS安全也包含很多内容,关于模板我们已经介绍了很多内容。XSS安全就简单介绍一下即可。
XSS主要分为三种,我们先测试其中一种。即通过提交待script标签的内容执行js。例如下面的html
layout.html加一个表单
一个最普通不过的表单。go的处理函数为:
提交一段js,可以看到go在表达处理的时候,自动帮我们做了xss过滤
当然,如果不想转义标签,需要使用template.HTML方法包裹:
开发者尤其要注意XSS的安全处理,然而XSS原不是这么简单,更多的内容请阅读安全相关的资料。
总结
关于go中的模板技术,我们已经掌握了不少内容。模板提供给了用户界面,最终是通过界面的交互,收集用户的数据。
数据存储将会是我们的下一个话题。
领取专属 10元无门槛券
私享最新 技术干货