复习tp3.23(六)(循环和控制输出,公共模板和模板布局)

ThinkPHP3.2.3循环和控制输出

我们来进一步了解如何进行模板数据的循环和控制输出。
注意,本篇的描述仅针对使用内部模板引擎的情况,如果你使用了Smarty或者其他模板引擎,请参考其相关的变量输出语法。

循环输出

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

$User = M('User');
$list = $User->limit(10)->select();
$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','没有数据');$this->assign('list',$list);

然后在模板中使用:

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

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

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

FOREACH

除了volist标签之外,还可以使用foreach标签,foreach标签类似与volist标签,只是更加简单,没有太多额外的属性,例如:

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

name 表示数据源 item表示循环变量。
foreach 标签还可以输出一维数组,例如:

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

条件输出

条件输出最常用的包括switch、if以及eq等比较标签。
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>

比较标签

比较标签用于简单的变量比较,复杂的判断条件可以用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>

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

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

范围判断标签

范围判断标签包括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 name="id" value="1,2,3">id不在范围内</notin>

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

<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变量可以是数组,也可以是以逗号分隔的字符串。

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>

赋值判断标签

可以使用present、empty等标签进行赋值判断输出。
present标签用于判断某个变量是否已经定义,用法:

<present name="name">name已经赋值<else /> name还没有赋值</present>

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

<present name="Think.get.name">$_GET['name']已经赋值

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

name为空
name不为空

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

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

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

<defined name="NAME">NAME常量已经定义<else /> NAME常量未定义</defined>

原生代码

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

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

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

 echo 'Hello,world!'; ?> 

ThinkPHP3.2.3公共模板和模板布局

我们学习了模板的输出后,就会发现很多应用存在大量的模板文件,如何简化模板文件的定义和公共调用就成了关键,ThinkPHP的模板引擎内置了公共模板和布局模板功能支持,可以方便的规划和公用你的模板文件。

公共模板

在当前模版文件中包含其他公用的模版文件使用include标签,标签用法:

<include file='模版表达式或者模版文件1,模版表达式或者模版文件2,...' />

使用模版表达式

模版表达式的定义规则为: 模块@主题/控制器/操作

例如:

<include file="Public/header" /> // 包含头部模版header
<include file="Public/menu" /> // 包含菜单模版menu
<include file="Blue/Public/menu" /> // 包含blue主题下面的menu模版

可以一次包含多个模版,例如:

<include file="Public/header,Public/menu" />

注意,包含模版文件并不会自动调用控制器的方法,也就是说包含的其他模版文件中的变量赋值需要在当前操作中完成。

使用模版文件

可以直接包含一个模版文件名(包含完整路径),例如:

<include file="./Application/Home/View/default/Public/header.html" />

传入参数
无论你使用什么方式包含外部模板,Include标签支持在包含文件的同时传入参数,例如,下面的例子我们在包含header模板的时候传入了title和keywords变量:

<include file="Public/header" title="ThinkPHP框架" keywords="开源WEB开发框架" />

就可以在包含的header.html文件里面使用title和keywords变量,如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>[title]</title>
<meta name="keywords" content="[keywords]" />
</head>

注意:如果外部模板有所更改,模板引擎并不会重新编译模板,除非在调试模式下或者缓存已经过期。如果部署模式下修改了包含的外部模板文件后,需要把模块的缓存目录清空,否则无法生效。

模板布局

有三种布局模板的支持方式:
第一种方式:全局配置方式
这种方式仅需在项目配置文件中添加相关的布局模板配置,就可以简单实现模板布局功能,比较适用于全站使用相同布局的情况,需要配置开启LAYOUT_ON 参数(默认不开启),并且设置布局入口文件名LAYOUT_NAME(默认为layout)。

'LAYOUT_ON'=>true,
'LAYOUT_NAME'=>'layout',

开启LAYOUT_ON后,我们的模板渲染流程就有所变化,例如:


namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller {
    Public function add() {
        $this->display('add');
    }
 }

在不开启LAYOUT_ON布局模板之前,会直接渲染Home/View/User/add.html 模板文件,开启之后首先会渲染Home/View/layout.html 模板布局模板的写法其他模板的写法类似,本身也可以支持所有的模板标签以及包含文件,区别在于有一个特定的输出替换变量{CONTENT},例如,下面是一个典型的layout.html模板的写法:

<include file="Public:header" />{__CONTENT__}<include file="Public:footer" />

读取layout模板之后,会再解析Home/View/User/add.html 模板文件,并把解析后的内容替换到layout布局模板文件的{CONTENT} 特定字符串。
采用这种布局方式的情况下,一旦Home/View/User/add.html 模板文件或者Home/View/layout.html布局模板文件发生修改,都会导致模板重新编译。
如果需要指定其他位置的布局模板,可以使用:

'LAYOUT_NAME'=>'Layout/layoutname',

就表示采用Home/View/Layout/layoutname.html作为布局模板。

如果某些页面不需要使用布局模板功能,可以在模板文件开头加上 {NOLAYOUT} 字符串。
如果上面的Home/View/User/add.html
模板文件里面包含有{NOLAYOUT},则即使当前开启布局模板,也不会进行布局模板解析。

第二种方式:模板标签方式

这种布局模板不需要在配置文件中设置任何参数,也不需要开启LAYOUT_ON,直接在模板文件中指定布局模板即可,相关的布局模板调整也在模板中进行。
以前面的输出模板为例,这种方式的入口还是在Home/View/User/add.html 模板,但是我们可以修改下add模板文件的内容,在头部增加下面的布局标签(记得首先关闭前面的LAYOUT_ON设置,否则可能出现布局循环):

<layout name="layout" />

表示当前模板文件需要使用Home/View/layout.html 布局模板文件,而布局模板文件的写法和上面第一种方式是一样的。当渲染Home/View/User/add.html 模板文件的时候,如果读取到layout标签,则会把当前模板的解析内容替换到layout布局模板的{CONTENT} 特定字符串。
一个模板文件中只能使用一个布局模板,如果模板文件中没有使用任何layout标签则表示当前模板不使用任何布局。
如果需要使用其他的布局模板,可以改变layout的name属性,例如:

<layout name="newlayout" />

还可以在layout标签里面指定要替换的特定字符串:

<layout name="Layout/newlayout"  replace="{__REPLACE__}" />

由于所有include标签引入的文件都支持layout标签,所以,我们可以借助layout标签和include标签相结合的方式实现布局模板的嵌套。例如,上面的例子

<include file="Public:header" />
<div id="main" class="main" >
{__CONTENT__}
</div>
<include file="Public:footer" />

在引入的header和footer模板文件中也可以添加layout标签,例如header模板文件的开头添加如下标签:

<layout name="menu" />

这样就实现了在头部模板中引用了menu布局模板。
也可以采用两种布局方式的结合,可以实现更加复杂的模板布局以及嵌套功能。

第三种方式:使用layout控制模板布局
**使用内置的layout方法可以更灵活的在程序中控制模板输出的布局功能,尤其适用于局部需要布局或者关闭布局的情况,这种方式也不需要在配置文件中开启LAYOUT_ON。**例如:


namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller {
    Public function add() {
        layout(true);
        $this->display('add');
    }
 }

表示当前的模板输出启用了布局模板,并且采用默认的layout布局模板。
如果当前输出需要使用不同的布局模板,可以动态的指定布局模板名称,例如:


namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller {
    Public function add() {
        layout('Layout/newlayout');
        $this->display('add');
    }
 }

或者使用layout方法动态关闭当前模板的布局功能(这种用法可以配合第一种布局方式,例如全局配置已经开启了布局,可以在某个页面单独关闭)


namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller {
    Public function add() {
        layout(false); // 临时关闭当前模板的布局功能
        $this->display('add');
    }
 }

三种模板布局方式中,第一种和第三种是在程序中配置实现模板布局,第二种方式则是单纯通过模板标签在模板中使用布局。具体选择什么方式,需要根据项目的实际情况来了。

你可能感兴趣的:(php大杂烩,tp3.23)