ThinkPHP5的模板标签库

Published on 2016 - 12 - 20

标签库

内置的模板引擎除了支持普通变量的输出之外,更强大的地方在于标签库功能。

标签库类似于Java的Struts中的JSP标签库,每一个标签库是一个独立的标签库文件,标签库中的每一个标签完成某个功能,采用XML标签方式(包括开放标签和闭合标签)。

标签库分为内置和扩展标签库,内置标签库是Cx标签库。

导入标签库

使用taglib标签导入当前模板中需要使用的标签库,例如:

{taglib name="html" /}

如果没有定义html标签库的话,则导入无效。

也可以导入多个标签库,使用:

{taglib name="html,article" /}

导入标签库后,就可以使用标签库中定义的标签了,假设article标签库中定义了read标签:

{article:read name="hello" id="data" }
{$data.id}:{$data.title}
{/article:read}

在上面的标签中,{article:read}... {/article:read}就是闭合标签,起始和结束标签必须成对出现。

如果是{article:read name="hello" /}就是开放标签。

闭合和开放标签取决于标签库中的定义,一旦定义后就不能混淆使用,否则就会出现错误。

内置标签

内置标签库无需导入即可使用,并且不需要加XML中的标签库前缀,ThinkPHP内置的标签库是Cx标签库,所以,Cx标签库中的所有标签,我们可以在模板文件中直接使用,我们可以这样使用:

{eq name="status" value="1" }
正常
{/eq}

如果Cx不是内置标签的话,可能就需要这么使用了:

{cx:eq name="status" value="1" }
正常
{/cx:eq}

内置标签库可以简化模板中标签的使用,所以,我们还可以把其他的标签库定义为内置标签库(前提是多个标签库没有标签冲突的情况),例如:

'taglib_build_in'    =>    'cx,article'

配置后,上面的标签用法就可以改为:

{read name="hello" id="data" }
{$data.id}:{$data.title}
{/read}

标签库预加载

标签库预加载是指无需手动在模板文件中导入标签库即可使用标签库中的标签,通常用于某个标签库需要被大多数模板使用的情况。

在应用或者模块的配置文件中添加:

'taglib_pre_load'    =>    'article,html'

设置后,模板文件就不再需要使用

{taglib name="html,article" /}

但是仍然可以在模板中调用:

{article:read name="hello" id="data" }
{$data.id}:{$data.title}
{/article:read}

内置标签

变量输出使用普通标签就足够了,但是要完成其他的控制、循环和判断功能,就需要借助模板引擎的标签库功能了,系统内置标签库的所有标签无需引入标签库即可直接使用。

内置标签包括:

标签名 作用 包含属性
include 包含外部模板文件(闭合) file
load 导入资源文件(闭合 包括js css import别名) file,href,type,value,basepath
volist 循环数组数据输出 name,id,offset,length,key,mod
foreach 数组或对象遍历输出 name,item,key
for For循环数据输出 name,from,to,before,step
switch 分支判断输出 name
case 分支判断输出(必须和switch配套使用) value,break
default 默认情况输出(闭合 必须和switch配套使用)
compare 比较输出(包括eq neq lt gt egt elt heq nheq等别名) name,value,type
range 范围判断输出(包括in notin between notbetween别名) name,value,type
present 判断是否赋值 name
notpresent 判断是否尚未赋值 name
empty 判断数据是否为空 name
notempty 判断数据是否不为空 name
defined 判断常量是否定义 name
notdefined 判断常量是否未定义 name
define 常量定义(闭合) name,value
assign 变量赋值(闭合) name,value
if 条件判断输出 condition
elseif 条件判断输出(闭合 必须和if标签配套使用) condition
else 条件不成立输出(闭合 可用于其他标签)
php 使用php代码

循环输出标签

VOLIST标签

volist标签通常用于查询数据集(select方法)的结果输出,通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出。 在控制器中首先对模版赋值:

$list = User::all();
$this->assign('list',$list);

在模版定义如下,循环输出用户的编号和姓名:

{volist name="list" id="vo"}
{$vo.id}:{$vo.name}<br/>
{/volist}

Volist标签的name属性表示模板赋值的变量名称,因此不可随意在模板文件中改变。id表示当前的循环变量,可以随意指定,但确保不要和name属性冲突,例如:

{volist name="list" id="data"}
{$data.id}:{$data.name}<br/>
{/volist}

支持输出查询结果中的部分数据,例如输出其中的第5~15条记录

{volist name="list" id="vo" offset="5" length='10'}
{$vo.name}
{/volist}

输出偶数记录

{volist name="list" id="vo" mod="2" }
{eq name="mod" value="1"}{$vo.name}{/eq}
{/volist}

Mod属性还用于控制一定记录的换行,例如:

{volist name="list" id="vo" mod="5" }
{$vo.name}
{eq name="mod" value="4"}<br/>{/eq}
{/volist}

为空的时候输出提示:

{volist name="list" id="vo" empty="暂时没有数据" }
{$vo.id}|{$vo.name}
{/volist}

empty属性不支持直接传入html语法,但可以支持变量输出,例如:

$this->assign('empty','<span class="empty">没有数据</span>');
$this->assign('list',$list);

然后在模板中使用:

{volist name="list" id="vo" empty="$empty" }
{$vo.id}|{$vo.name}
{/volist}

输出循环变量:

{volist name="list" id="vo" key="k" }
{$k}.{$vo.name}
{/volist}

如果没有指定key属性的话,默认使用循环变量i,例如:

{volist name="list" id="vo"  }
{$i}.{$vo.name}
{/volist}

如果要输出数组的索引,可以直接使用key变量,和循环变量不同的是,这个key是由数据本身决定,而不是循环控制的,例如:

{volist name="list" id="vo"  }
{$key}.{$vo.name}
{/volist}

模板中可以直接使用函数设定数据集,而不需要在控制器中给模板变量赋值传入数据集变量,如:

{volist name=":fun('arg')" id="vo"}
{$vo.name}
{/volist}

FOREACH标签

foreach标签类似与volist标签,只是更加简单,没有太多额外的属性,最简单的用法是:

{foreach $list as $vo} 
    {$vo.id}:{$vo.name}
{/foreach}

该用法解析后是最简洁的。

也可以使用下面的用法:

{foreach name="list" item="vo"}
    {$vo.id}:{$vo.name}
{/foreach}

name表示数据源 item表示循环变量。

可以输出索引,如下:

{foreach name="list" item="vo" }
    {$key}|{$vo}
{/foreach}

也可以定义索引的变量名

{foreach name="list" item="vo" key="k" }
   {$k}|{$vo}
{/foreach}

FOR标签

用法:

{for start="开始值" end="结束值" comparison="" step="步进值" name="循环变量名" }
{/for}

开始值、结束值、步进值和循环变量都可以支持变量,开始值和结束值是必须,其他是可选。comparison 的默认值是lt,name的默认值是i,步进值的默认值是1,举例如下:

{for start="1" end="100"}
{$i}
{/for}

解析后的代码是

for ($i=1;$i<100;$i+=1){
    echo $i;
} 

比较标签

比较标签用于简单的变量比较,复杂的判断条件可以用if标签替换,比较标签是一组标签的集合,基本上用法都一致,如下:

{比较标签 name="变量" value="值"}
内容
{/比较标签}

系统支持的比较标签以及所表示的含义分别是:

标签 含义
eq或者 equal 等于
neq 或者notequal 不等于
gt 大于
egt 大于等于
lt 小于
elt 小于等于
heq 恒等于
nheq 不恒等于

他们的用法基本是一致的,区别在于判断的条件不同,并且所有的比较标签都可以和else标签一起使用。

例如,要求name变量的值等于value就输出,可以使用:

{eq name="name" value="value"}value{/eq}

或者

{equal name="name" value="value"}value{/equal}

也可以支持和else标签混合使用:

{eq name="name" value="value"}
相等
{else/}
不相等
{/eq}

当 name变量的值大于5就输出

{gt name="name" value="5"}value{/gt}

当name变量的值不小于5就输出

{egt name="name" value="5"}value{/egt}

比较标签中的变量可以支持对象的属性或者数组,甚至可以是系统变量,例如: 当vo对象的属性(或者数组,或者自动判断)等于5就输出

{eq name="vo.name" value="5"}
{$vo.name}
{/eq}

当vo对象的属性等于5就输出

{eq name="vo:name" value="5"}
{$vo.name}
{/eq}

当$vo['name']等于5就输出

{eq name="vo['name']" value="5"}
{$vo.name}
{/eq}

而且还可以支持对变量使用函数 当vo对象的属性值的字符串长度等于5就输出

{eq name="vo:name|strlen" value="5"}{$vo.name}{/eq}

变量名可以支持系统变量的方式,例如:

{eq name="Think.get.name" value="value"}相等{else/}不相等{/eq}

通常比较标签的值是一个字符串或者数字,如果需要使用变量,只需要在前面添加“$”标志: 当vo对象的属性等于$a就输出

{eq name="vo:name" value="$a"}{$vo.name}{/eq}

所有的比较标签可以统一使用compare标签(其实所有的比较标签都是compare标签的别名),例如: 当name变量的值等于5就输出

{compare name="name" value="5" type="eq"}value{/compare}

等效于

{eq name="name" value="5" }value{/eq}

其中type属性的值就是上面列出的比较标签名称

条件判断

SWITCH标签

用法:

{switch name="变量" }
    {case value="值1" break="0或1"}输出内容1{/case}
    {case value="值2"}输出内容2{/case}
    {default /}默认情况
{/switch}

使用方法如下:

{switch name="User.level"}
    {case value="1"}value1{/case}
    {case value="2"}value2{/case}
    {default /}default
{/switch}

其中name属性可以使用函数以及系统变量,例如:

{switch name="Think.get.userId|abs"}
    {case value="1"}admin{/case}
    {default /}default
{/switch}

对于case的value属性可以支持多个条件的判断,使用”|”进行分割,例如:

{switch name="Think.get.type"}
    {case value="gif|png|jpg"}图像格式{/case}
    {default /}其他格式
{/switch}

表示如果$_GET["type"]是gif、png或者jpg的话,就判断为图像格式。

Case标签还有一个break属性,表示是否需要break,默认是会自动添加break,如果不要break,可以使用:

{switch name="Think.get.userId|abs"}
    {case value="1" break="0"}admin{/case}
    {case value="2"}admin{/case}
    {default /}default
{/switch}

也可以对case的value属性使用变量,例如:

{switch name="User.userId"}
    {case value="$adminId"}admin{/case}
    {case value="$memberId"}member{/case}
    {default /}default
{/switch}

使用变量方式的情况下,不再支持多个条件的同时判断。

简洁的用法

{switch $User.userId}
    {case $adminId}admin{/case}
    {case $memberId}member{/case}
{/switch}

IF标签

用法示例:

{if condition="($name == 1) OR ($name > 100) "} value1
{elseif condition="$name eq 2"/}value2
{else /} value3
{/if}

除此之外,我们可以在condition属性里面使用php代码,例如:

{if condition="strtoupper($user['name']) neq 'THINKPHP'"}ThinkPHP
{else /} other Framework
{/if}

condition属性可以支持点语法和对象语法,例如: 自动判断user变量是数组还是对象

{if condition="$user.name neq 'ThinkPHP'"}ThinkPHP
{else /} other Framework
{/if}

或者知道user变量是对象

{if condition="$user:name neq 'ThinkPHP'"}ThinkPHP
{else /} other Framework
{/if}

由于if标签的condition属性里面基本上使用的是php语法,尽可能使用判断标签和Switch标签会更加简洁,原则上来说,能够用switch和比较标签解决的尽量不用if标签完成。因为switch和比较标签可以使用变量调节器和系统变量。如果某些特殊的要求下面,IF标签仍然无法满足要求的话,可以使用原生php代码或者PHP标签来直接书写代码。

简洁的用法

{if condition="表达式"}
{if (表达式)}
{if 表达式}

这三种写法结果是一样的

范围判断

范围判断标签包括in notin between notbetween四个标签,都用于判断变量是否中某个范围。

IN和NOTIN

用法: 假设我们中控制器中给id赋值为1:

$id =    1;
$this->assign('id',$id);

我们可以使用in标签来判断模板变量是否在某个范围内,例如:

{in name="id" value="1,2,3"}
id在范围内
{/in}

最后会输出:id在范围内。

如果判断不在某个范围内,可以使用notin标签:

{notin name="id" value="1,2,3"}
id不在范围内
{/notin}

最后会输出:id不在范围内。

可以把上面两个标签合并成为:

{in name="id" value="1,2,3"}
id在范围内
{else/}
id不在范围内
{/in}

name属性还可以支持直接判断系统变量,例如:

{in name="Think.get.id" value="1,2,3"}
$_GET['id'] 在范围内
{/in}

value属性也可以使用变量,例如:

{in name="id" value="$range"}
id在范围内
{/in}

$range变量可以是数组,也可以是以逗号分隔的字符串。

value属性还可以使用系统变量,例如:

{in name="id" value="$Think.post.ids"}
id在范围内
{/in}

BETWEEN 和 NOTBETWEEN

可以使用between标签来判断变量是否在某个区间范围内,可以使用:

{between name="id" value="1,10"}
输出内容1
{/between}

同样,也可以使用notbetween标签来判断变量不在某个范围内:

{notbetween name="id" value="1,10"}
输出内容2
{/notbetween}

也可以使用else标签把两个用法合并,例如:

{between name="id" value="1,10"}
输出内容1
{else/}
输出内容2
{/between}

当使用between标签的时候,value只需要一个区间范围,也就是只支持两个值,后面的值无效,例如

{between name="id" value="1,3,10"}
输出内容1
{/between}

实际判断的范围区间是1~3,而不是1~10,也可以支持字符串判断,例如:

{between name="id" value="A,Z"}
输出内容1
{/between}

name属性可以直接使用系统变量,例如:

{between name="Think.post.id" value="1,5"}
输出内容1
{/between}

value属性也可以使用变量,例如:

{between name="id" value="$range"}
输出内容1
{/between}

变量的值可以是字符串或者数组,还可以支持系统变量。

{between name="id" value="$Think.get.range"}
输出内容1
{/between}

RANGE

也可以直接使用range标签,替换前面的判断用法:

{range name="id" value="1,2,3" type="in"}
输出内容1
{/range}

其中type属性的值可以用in/notin/between/notbetween,其它属性的用法和IN或者BETWEEN一致。

PRESENT NOTPRESENT标签

present标签用于判断某个变量是否已经定义,用法:

{present name="name"}
name已经赋值
{/present}

如果判断没有赋值,可以使用:

{notpresent name="name"}
name还没有赋值
{/notpresent}

可以把上面两个标签合并成为:

{present name="name"}
name已经赋值
{else /}
name还没有赋值
{/present}

present标签的name属性可以直接使用系统变量,例如:

{present name="Think.get.name"}
$_GET['name']已经赋值
{/present}

EMPTY NOTEMPTY 标签

empty标签用于判断某个变量是否为空,用法:

{empty name="name"}
name为空值
{/empty}

如果判断没有赋值,可以使用:

{notempty name="name"}
name不为空
{/notempty}

可以把上面两个标签合并成为:

{empty name="name"}
name为空
{else /}
name不为空
{/empty}

name属性可以直接使用系统变量,例如:

{empty name="Think.get.name"}
$_GET['name']为空值
{/empty}

DEFINED 标签

DEFINED标签用于判断某个常量是否有定义,用法如下:

{defined name="NAME"}
NAME常量已经定义
{/defined}

name属性的值要注意严格大小写

如果判断没有被定义,可以使用:

{notdefined name="NAME"}
NAME常量未定义
{/notdefined}

可以把上面两个标签合并成为:

{defined name="NAME"}
NAME常量已经定义
{else /}
NAME常量未定义
{/defined}

资源文件加载

传统方式的导入外部JS和CSS文件的方法是直接在模板文件使用:

<script type='text/javascript' src='/static/js/common.js'>
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />

系统提供了专门的标签来简化上面的导入:

{load href="/static/js/common.js" /}
{load href="/static/css/style.css" /}

并且支持同时加载多个资源文件,例如:

{load href="/static/js/common.js,/static/css/style.css" /}

系统还提供了两个标签别名js和css 用法和load一致,例如:

{js href="/static/js/common.js" /}
{css href="/static/css/style.css" /}

标签嵌套

模板引擎支持标签的多层嵌套功能,可以对标签库的标签指定可以嵌套。

系统内置的标签中,volist、switch、if、elseif、else、foreach、compare(包括所有的比较标签)、(not)present、(not)empty、(not)defined等标签都可以嵌套使用。例如:

{volist name="list" id="vo"}
    {volist name="vo['sub']" id="sub"}
        {$sub.name}
    {/volist}
{/volist}

上面的标签可以用于输出双重循环。

原生PHP

Php代码可以和标签在模板文件中混合使用,可以在模板文件里面书写任意的PHP语句代码 ,包括下面两种方式:

使用php标签

例如:

{php}echo 'Hello,world!';{/php}

我们建议需要使用PHP代码的时候尽量采用php标签,因为原生的PHP语法可能会被配置禁用而导致解析错误。

使用原生php代码

<?php echo 'Hello,world!'; ?>

注意:php标签或者php代码里面就不能再使用标签(包括普通标签和XML标签)了,因此下面的几种方式都是无效的:

{php}{eq name='name'value='value'}value{/eq}{/php}

Php标签里面使用了eq标签,因此无效

{php}if( {$user} != 'ThinkPHP' ) echo  'ThinkPHP' ;{/php}

Php标签里面使用了{$user}普通标签输出变量 ,因此无效。

{php}if( $user.name != 'ThinkPHP' ) echo  'ThinkPHP' ;{/php}

Php标签里面使用了$user.name 点语法变量输出 ,因此无效。

简而言之,在PHP标签里面不能再使用PHP本身不支持的代码。

如果设置了tpl_deny_php参数为true,就不能在模板中使用原生的PHP代码,但是仍然支持PHP标签输出。

定义标签

ASSIGN标签

ASSIGN标签用于在模板文件中定义变量,用法如下:

{assign name="var" value="123" /}

在运行模板的时候,赋值了一个var的变量,值是123。

name属性支持系统变量,例如:

{assign name="Think.get.id" value="123" /}

表示在模板中给$_GET['id'] 赋值了 123

value属性也支持变量,例如:

{assign name="var" value="$val" /}

或者直接把系统变量赋值给var变量,例如:

{assign name="var" value="$Think.get.name" /}

相当于,执行了:$var = $_GET['name'];

DEFINE标签

DEFINE标签用于中模板中定义常量,用法如下:

{define name="MY_DEFINE_NAME" value="3" /}

在运行模板的时候,就会定义一个MY_DEFINE_NAME的常量。

value属性可以支持变量(包括系统变量),例如:

{define name="MY_DEFINE_NAME" value="$name" /}

或者

{define name="MY_DEFINE_NAME" value="$Think.get.name" /}

参考文档