RainTPL模板
模板引擎
模板引擎是渲染生成HTML页面的工具程序,它可以把数据嵌入到html代码中,动态地生成完整的页面。许多人认为PHP本身就是模板引擎,因为它可以支持直接嵌入在html页面中书写代码。不过我认为还是有使用模板引擎的必要,因为直接嵌入的PHP代码如果不对数据做检查,就可能会被报出notice或者warning,如果加上检查数据类型的代码,又太难看了。
PHP老牌的模板引擎是Smarty,xts在选择模板引擎的时候也曾考虑使用它,不过由于Smarty性能相对比较差,就没有作为xts首选的模板引擎。xts选择了更轻更快的RainTPL作为模板引擎,为了更贴合xts中的使用现状,我将RainTPL加以修改,改写成了xts\HailStone
类。
RainTPL模板语法
变量
变量的语法和Smarty很像,直接由花括号括起变量名就是。下面是Hello, world例子中的模板:
<h2>Hello, {$to}</h2>
RainTPL也支持对变量使用modifier:
<date>{$order.timestamp|date:%Y-%m-%d}</date>
可以输出带+、-、*、/、%运算符的变量表达式:
<div>{$a} + {$b} = {$a+$b}</div>
如果需要使用_SESSION, _GET, _POST, _SERVER等超全局变量,请使用{$GLOBALS}访问
注意:RainTPL不支持修改边界为其它字符,花括号是直接写死在代码里的
常量
好像模板引擎需要输出常量的情况不多,不过还是可以支持,用花括号加井号的语法:
{#X_PROJECT_ROOT#}
if语句
if语法和PHP的一样,可以直接地condition中使用PHP变量和表达式。
{if condition="$age < 20"}
less than 20 years
{elseif condition="$age < 30"}
less than 30 years
{else}
30 or more
{/if}
循环
RainTPL只支持foreach循环
{loop="$items"}
<a href="/show?id={$value.id}">{$value.name}</a>
{/loop}
在循环中,可以使用三个变量
- $key 是当前数组元素的键
- $value 是当前数组元素的值
- $counter 是循环计数器,从0开始
引用其它模板
可以用include引入其它模板
{include="common/header_partial"}
引入其它模板的时候,模板文件扩展名可以省略,xts会默认使用.html
当后缀
调用函数
可以在模板中调用PHP函数
{function="pagination($selected_page)"}
RainTPL会打印出函数运行的结果。
模板注释
模板注释的语法和Smarty一样
{* 这是注释 *}
还有一种写法更友善一些
{ignore}
这里都是注释
{/ignore}
原样输出
写在{noparse}
和{/noparse}
之间的东西会原样输出
<script type="text/javascript">
{noparse}
var f = {status: 5};
{/noparse}
</script>
xts中的模板
xts中的模板需要实现xts\View
接口。这个接口要求模板引擎实现setPagetTitle、setLayout等一系列方法。一般模板需要在每个页面include进来header和footer,xts的模板则反过来,在layout中include具体页面的模板,具体的模板名称通过render函数的参数传递。
X::view()
->setPageTitle('Hello world')
->render('index', array(
'to' => 'world',
), '1');
在这个例子中,X::view()
返回了模板引擎类,setPageTitle设置页面的标题。render函数第一个参数是模板名称,这里表示要渲染的模板名为index;第二个参数是赋给模板引擎的变量数组,这个数组里的Key会成为模板中的变量名称;第三个参数是模板渲染后缓存的key。
一般网站都会在各个页面共用header和footer,虽然模板引擎提供了include支持,但是在每个页面的模板上都include头尾非常不便。xts的模板采用了布局模板include内容模板的反向引用方式,在render函数中指定的模板名称是内容模板的名称,会在默认名为layout的模板中把它include进来。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<style media="handheld" type="text/css"></style>
<link rel="stylesheet" href="/static/css/common.css">
<title>{$_page_title|escape}</title>
</head>
<body>
{include="$_content_template"}
</body>
</html>
上面是布局模板的范例,在<body>
标签中引用了内容模板,内容模板的例子在下面。
<h2>Hello, {$to}</h2>
更改Layout
有的时候,网站中会出现部分页面布局不同的情况,header和footer和其它页面有所不同,这时候可以定义一个新的layout,然后直接用setLayout
函数更新layout模板的名字。
X::view()->setLayout('new_layout')
->render('special_page');
在内容模板中输出外部css和js
内容页面常常需要引入一些外部的css文件以及js文件,需要把这些css引用写到layout的首部,把js引用写到layout的尾部。因为这些都是属于纯前端的东西,如果在PHP里assign一个变量然后输出会非常不友好。在把RainTPL移植到xts之后,我扩展了一个剪辑定义和输出的功能来解决这个问题。
可以在layout中留下剪辑输出的代码:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<style media="handheld" type="text/css"></style>
<link rel="stylesheet" href="/static/css/common.css">
{clip="css"}
<title>{$_page_title|escape}</title>
</head>
<body>
{include="$_content_template"}
{clip="js"}
</body>
</html>
在内容模板中可以定义剪辑的内容,clipdef可以支持多次定义,xts会追加处理:
{clipdef="css"}<link rel="stylesheet" href="/static/css/index.css">{/clipdef}
{clipdef="css"}<link rel="stylesheet" href="/static/css/nothing.css">{/clipdef}
<h2>Hello, {$to}</h2>
{clipdef="js"}
<script src="/static/js/index.js"></script>
<script src="/static/js/checker.js"></script>
{/clipdef}
clip和clipdef是HailStone扩展的语法,它们的位置可以在任何模板中使用。clipdef的内容会在HailStone渲染页面的时候处理生成,完成渲染后替换到同名的clip位置上。
注意:需要在配置文件里把enable_clip
设置为true
才能使用此功能。
取回渲染好的html
有的时候不并希望渲染好的页面直接输出到浏览器上,而是希望能把页面html以字符串的方式取回。可以调用renderFetch函数来达成这一目的
X::view()->renderFetch('index', array(
'to' => 'world',
), '1');
renderFetch函数的参数和render函数完全相同,唯一的区别是返回值不同。
请教: 模板里面使用:<srcipt src="//google.com/a.js" 类似自适应代码,会出现解析错误,变成 /google.com。有解决办法吗
你用的什么版本的raintpl?