Mather

We create our own demons.

ThinkPHP5 模板引擎 使用备忘

默认分类 0 评

ThinkPHP 内置的模板引擎来定义模板文件,以及使用加载文件、模板布局和模板继承等高级功能。

每个模板文件在执行过程中都会生成一个编译后的缓存文件,其实就是一个可以运行的 PHP 文件。

引用自 http://www.kancloud.cn/manual/thinkphp5/118122

开门见山

PHP

/*index/controller/example.php*/

use thinkController;

class test extends Index {

    public function template (){
        $name = 'Jerry';
        $allName = [
            0 => "Jerry",
            1 => "Tom"
        ];

        $this->assign('nameA',$name);
        $this->assign('allNameA',$allName);

        return $this->fetch('example');
    }
}

HTML

/*index/view/example.html*/

<span>{$nameA}</span>

{volist name="allNameA" id="vo"}
    
    <p data-sub="{$key}" data-index="{$i}">{$vo}</p>

{/volist}

Result


<span>Jerry</span>

<p data-sub="0" data-index="1">Jerry</p>

<p data-sub="1" data-index="2">Tom</p>

这样 ThinkPHP 便完成了对页面的解析工作,其中涉及到 模板实例化、定位、赋值、渲染及标签的使用。


视图实例化

暂无

模板赋值

显然在在模板中直接使用 $name 是找不到该变量的。必须使用 assign 方法对模板赋值。在执行渲染输出函数前,assign 方法使 函数内部变量与模板变量建立起映射关系。

$this->assign('nameA',$name);
$this->assign('allNameA',$allName);

通过赋值之后,便可以使用自定义的 {$nameA} 来输出该变量了。

模板渲染

当数据已经准备好渲染到页面上,还需要指定 html 文件作为渲染模板,为当前函数执行 fetch 方法时候传入 example 参数。

 return $this->fetch('example');//example is a html file.

模板标签

在模板文件中使用的内置标签可以帮助我们在模板中循环、判断变量,它以一对花括号 {tagName} {/tagName}作为开标签和闭标签。 标签的{}之间必须紧跟标签属性或值,存在 空格换行不能被正常解析。

volist 标签就是内置标签中的其中一个,通常用来循环某个数组变量。

{volist name="allNameA" id="vo"}
    <p data-sub="{$key}" data-index="{$i}">{$vo}</p>
{/volist}

allName 是通过模板赋值的变量 ,现在可以在模板上直接使用了,显然它是一个数组,volist 标签对它做了循环操作。

volist 标签常用的一些属性:

propArray NameCurrent Ele
keynameid
valueallNamevo

隐藏在 volist 中的有几个内部变量 {$key} {$i} ,分别代表了 数组下标循环次数
volist 一样好用的内置标签还有很多:

内置标签

比较功能:
{eq name="data.status" value="0"}
    0
    {else/}
    not equal 0
{/eq}

eq 标签像是一个 if 语句,同样能判断变量的值是否相同;而 neq 标签则相反。

条件判断功能:
{switch name="data.status"}
    {case value="0"}0{/case}
    {case value="1"}1{/case}
    {case value="2"}2{/case}
    {default /}10
{/switch}

switch 标签否相等。
比较 data.status 对象中 status 的值是否等于 value的值,等于则执行对应标签内的内容;
若所有 {case} 都不符合,则执行 {default /}

{if condition="boole_one"} value1
    {elseif condition="boole_two"/}both
    {else /}nothing
{/if}

当然还有复杂一点的 if 标签,用于判断复杂表达式是否成立。

其他:
//HTML
{assign name="username" value="Tom" /}

<p>{$username}</p>

assign 标签能在渲染模板时在模板中声明变量,以便在渲染时直接使用。该标签往往配合其他标签使用。

{notempty name="username"}{/notempty}

notempty 判断 username 变量是否存在, 不存在则进入下一层

{empty name="username"}{/empty}

empty 判断 username 变量是否存在, 存在则进入下一层

显然,相互嵌套的标签可以达到逻辑控制的效果,避免重复编写模板文件。


模板继承

在开发后台系统时,可能非常多管理页面都是基于一个共同的布局。侧边栏、顶部栏、页脚都是相同的布局,这些代码可以共用一个页面文件,使用 {block}{/block} 标签可以实现。

不妨先写一个基础的模板:

//base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    {block name="style"}
    {/block}
</head>
<body>
    <div class="wrapper">
        {block name="wrapperHeader"}
        {/block}

        {block name="content"}
        {/block}

        {include file="Public:footer" /}
    </div>
    {block name="script"}
    {/block}
</body>
</html>

base.html 中编写好后台页面的整体结构, 页面中有时候不止有一个 block 块,在不同位置可以插入样式、内容或者脚本,这很大的原因决定于一些前端页面的规划,比如基于 bootstrap 框架的 AdminLTE

对于 {block name="content"}{/block} 来说,在控制器中 fetch("example") 页面时,example.html 得先通过 {extend} 声明是要继承 base.html 页 。

//example.html
{extend name="Public:base" /}

{block name="content"}
    <section class="content">
        <p>This is example.html</p>
    </section>
{/block}

在约定好的地方使用 {block name="content"}{/block} 以替换 .wrapper 下的 content 块。

继承事先写好的 base.html ,这种用法在编写模板页文件时会减少非常多的代码量。

//result base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div class="wrapper">
        <section class="content">
            <p>This is example.html</p>
        </section>
    </div>
</body>
</html>

引入模板

啥? {block} 不够强力? {include /} 可能是拆分模板的好方法。

当业务中需要查看当前的详细信息时,信息页往往由非常多数据组成。如果按照权限划分,显示给用户是不同的一些信息,出现的可能性将会更多。

直接在模板中引入其他模板文件,诸多模板文件成为了组件,减少了模板之间的冗余。

//exampleOrder.html
<section class="content">
    <!--orderInfo-->
    {include file="Public/order/orderInfo"/}
    <!--orderTableCount-->
    <div class="box">
        {include file="Public/order/orderTableCount"/}
    </div>
    <div class="row">
        <!--orderRecord-->
        {include file="Public/order/orderRecord"/}
        <!--orderImage-->
        {include file="Public/order/orderImage"/}
    </div>
</section>

Public/order 目录下的模板文件 orderInfoorderTableorderRecordorderImage 都被引入到了 exampleOrder.html 中。

orderInfo.html

<p>this is a order info page.</p>

orderRecord.html

<p>this is a order record page.</p>

orderImage.html

<p>this is a order image page.</p>

orderTable.html

{volist name="list" id="vo"} {/volist}
Name Age Country
{$vo.name} {$vo.age} {$vo.country}

在被引入的页面中可以正常使用任何的 模板标签 或继续 引入 其他模板。

这样通过引用固定的模板,避免多个相同的页面存在,往后修改一处地方,引用该页面的模板也会做出相应的变动,对业务系统的修改起来非常省心。

如果渲染的父页面存在差异性,在父页面编写差异代码,则需继续细化引入的子页面,子页面再 {include /} 子页面能解决问题,但这会增加模板文件的数量。

<!--result exampleOrder.html-->
<section class="content">
    <!--orderInfo-->
    <p>this is a order info page.</p>
    <!--orderTableCount-->
    <div class="box">
        <table class="table table-bordered table-hover">
            <tbody>
                <tr>
                    <th>Name</th>
                    <th>Age</th>
                    <th>Country</th>
                </tr>
                <tr>
                    <td>Jane</td>
                    <td>13</td>
                    <td>USA</td>
                </tr>
                <tr>
                    <td>xiaoMing</td>
                    <td>14</td>
                    <td>China</td>
                </tr>
            </tbody>
        </table>
    </div>
    <div class="row">
        <!--orderRecord-->
        <p>this is a order record page.</p>
        <!--orderImage-->
        <p>this is a order image page.</p>
    </div>
</section>

思考与抉择

放眼一看,模板嵌套和模板引入都能实现差不多的需求,却是存在不同的差异。

模板继承 {block} 渲染(fetch)的是一个子页面,子页面继承了原有的主体框架。

引入模板 {include /} 渲染的是一主页面,在主页面中引入子页面来共同组成一个新页面。

当然,渲染页面不仅仅局限于这来两个种方案,还有非常多的组合方式。

在传统 MVC 应用中,页面的渲染功能往往交由后端完成,模板引擎具有的一些功能使得渲染页面变得更加方便,这意味着前端的任务仅仅是编写 HTML + CSS + JavaScript 组合式的代码吗? 为了进一步提升用户交互,我们有了 Ajax iframe,可是在前端并不满足处于被动状态的视图渲染方式。

早些年,一些前端应用框架逐渐发展起来,企图夺取页面的渲染权,掌管与后端的数据交换,为复杂的单页面应用提供驱动。这样,前端应用变得更像移动端的 App 一样百花怒放。

Vue.js 便是一款前端现代化框架。

Select2 更好的下拉列表(下)

发表评论
撰写评论