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函数完全相同,唯一的区别是返回值不同。

标签: xts

已有 2 条评论

  1. linkrain linkrain

    请教: 模板里面使用:<srcipt src="//google.com/a.js" 类似自适应代码,会出现解析错误,变成 /google.com。有解决办法吗

    1. xts xts

      你用的什么版本的raintpl?

添加新评论