模版引擎驱动和赋值变量
引擎驱动
MVC
中,M(模型)和 C(控制器)是前面我们所了解的内容,而V(视图)就是页面;- TP6.0 默认不自带
TT
模版引擎,它作为一个可选的扩展给开发人员安装; - 也就是说,并不一定非要使用模板引擎的语法规则来开发V(视图)部分;
- 如果不用模版引擎,可以在控制器通过
require()
方法引入PHP文件混编即可; - 如果要使用模版引擎,先创建一个用于测试模板引擎的控制器:
Show.php
; - 写入模版引擎的调用语法,来判断,是否已经安装了模板引擎扩展;
return View::fetch('index'); //出现缺少驱动的错误
- 然后,安装如下驱动后,再刷新页面即可;
composer require topthink/think-view
赋值变量
- 在控制器区域,通过
assign()
设置一个向模版提供变量的赋值操作;
View::assign('name', 'Mr.Lee');
- 而模版区域,只需要通过{$name}的语法即可获取到控制器设置的值;
{$name}
assign()
方法,支持通过数组的方式,传递模版变量;
View::assign(['name' => 'Mr.Lee','age' => 100]);
- 也可以直接通过
fetch()
方法的第二参数,直接用数组传递模版变量;
return View::fetch('index', ['name' => 'Mr.Lee','age' => 100]);
- 助手函数
view()
,和View::fetch()
一样;
return view('index', [...]);
- 可以使用
filter()
方法,对所有模版的变量进行过滤操作;
return View::filter(function ($content) {
return strtoupper($content);
})->fetch('index');
return view('index')->filter(function ($content) {
return strtoupper($content);
});
模版引擎配置和渲染
模版配置
- 默认情况下,
config/view.php
就是默认模版引擎的配置文件; - 内部的配置注释写的非常清楚了,一般情况下,不需要任何改动;
模版渲染
- 除了在配置文件修改外,还可以在控制器端动态修改模版配置;
View::config(['view_dir_name' => 'view2']);
- 默认情况下,调用的是本控制器的模版文件,也可以调用其它控制器的模版文件;
return View::fetch('Address/index');
- 如果你是多模块(多应用)模式下,也可以实现跨模块调用模版文件;
return View::fetch('admin@User/index');
- 如果直接在
view
根目录下的模版文件,用一个斜杠来设定即可调用;
return View::fetch('/index');
- 如果想调用
public
公共目录的模版文件,用../public
后面跟着URL即可;
return View::fetch('../public/test/test);
- 这种做法的调用方式,和模版引擎调用一样,只不过通信的数据获取方式有差异;
return View::engine('php')->fetch('index');
- 第二种原生PHP执行方式,在
return
之前设置的变量或者模版变量均无效; - 而是把所有的要传递的变量,通过
fetch()
的第二个参数传递;
return View::engine('php')->fetch('index', [
'name' => 'Mr.Lee',
'age' => 100
]);
模版的变量输出
变量输出
- 当程序运行的时候,会在
runtime/temp
目录下生成一个编译文件; - 默认情况下,输出的模版变量会自动进行过滤,过滤函数默认如下:
<?php echo htmlentities($name); ?>
- 如果传递的值是数组,在模版区域可以使用
$data.name
这种形式输出;
$arr = ['name'=>'Mr.Lee', 'age'=>100];
return View::fetch('output', [
'arr' => $arr
]);
{$arr.name}--{$arr.age} //模版数组变量输出
<?php echo htmlentities($arr['name']); ?> //编译文件
- 如果传递的值是对象,那么编译文件也会自动相应的对应输出方式;
public $name = 'Mr.Lee';
public $age = 'age';
const PI = 3.14;
return View::fetch('index', [
'obj' => $this,
]);
{$obj->name}--{$obj->age}--{$obj::PI}
<?php echo htmlentities($obj->name); ?> //编译文件
其它输出
- 如果输出的变量没有值,可以直接设置默认值代替;
{$data.name|default='没有姓名'}
- 系统变量有:
$_SERVER
,$_ENV
,$_GET
,$_POST
,$_REQUEST
,$_SESSION
,$_COOKIE
; - 对于注入
Request
对象,也可以直接在模版输出;
{$Request.get.id}
{$Request.param.name}
{$Request.host}
- 常量
,
配置信息等都可以通过$Think
输出;
{$Think.const.PHP_VERSION}
{$Think.PHP_VERSION}
{$Think.config.app.app_host}
{$Think.config.session.name}
模版的函数和运算符
使用函数
- 控制器端先赋值一个密码的变量,模版区设置
md5
加密操作;
{$password|md5}
- 如果在某个字符,你不需要进行HTML实体转义的话,可以单独使用
raw
处理;
{$user|raw}
- 系统还提供了一些固定的过滤方法,如下:
函数 | 说明 |
---|---|
date | 格式化时间{$time|date='Y-m-d'} |
format | 格式化字符串{$number|format='%x'} |
upper | 转换为大写 |
lower | 转换为小写 |
first | 输出数组的第一个元素 |
last | 输出数组的最后一个元素 |
default | 默认值 |
raw | 不使用转义 |
{$time|date='Y-m-d'}
{$number|format='%x'}
- 如果函数中,需要多个参数调用,直接用逗号隔开即可;
{$name|substr=0,3}
- 在模版中也支持多个函数进行操作,用
|
号隔开即可,函数从左到右依次执行;
{$password|md5|upper|substr=0,3}
- 你也可以在模版中直接使用 PHP 的语法模式,该方法不会使用过滤转义:
{:substr(strtoupper(md5($password)), 0, 3)}
运算符
- 在模版中的运算符有
+
,-
,*
,/
,%
,++
,--
等;
{$number + $number}
- 如果模版中有运算符,部分函数不支持;
{$number + $number|default='没有值'}
- 模版也可以实现三元运算,包括其它写法;
{$name ? '正确' : '错误'} //$name 为 true 返回正确,否则返回错误
{$name ?= '真'} //$name 为 true 返回真
{$Request.get.name ?? '不存在'} //??用于系统变量,没有值时输出
{$name ?: '不存在'} //?:用于普通变量,没有值时输出
- 三元运算符也支持运算后返回布尔值判断;
{$a == $b ? '真' : '假'}
模版的循环标签
foreach循环
- 控制前端先通过模型把相应的数据列表给筛选出来;
$list = User::select();
return View::fetch('loop', [
'list' => $list
]);
- 在模版端使用对称的标签
{foreach}...{/foreach}
实现循环; - 注意:这里对象调用时:用
->
符号或用.
符号均可正确实现数据显示;
{foreach $list as $key=>$obj}
<tr>
<td>{$key}/{$obj->id}</td> //{$obj.id}也行
<td>{$obj->username}</td>
<td>{$obj->gender}</td>
<td>{$obj->email}</td>
<td>{$obj->price}</td>
<td>{$obj->create_time}</td>
</tr>
{/foreach}
volist循环
- volist 也是将查询得到的数据集通过循环的方式进行输出;
{volist name="list" id="obj"}
<tr>
<td>{$key}/{$obj->id}</td> //{$obj.id}也行
<td>{$obj->username}</td>
<td>{$obj->gender}</td>
<td>{$obj->email}</td>
<td>{$obj->price}</td>
<td>{$obj->create_time}</td>
</tr>
{/volist}
volist
中的name
属性表示数据总集,id
属性表示当前循环的数据单条集;- 使用
offset
属性和length
属性从第4条开始显示5条,这里下标从0开始;
{volist name="list" id="obj" offset='3' length='5'}
- 可以使用
eq
标签,来实现奇数或偶数的筛选数据;
{volist name="list" id="obj" mod="2"}
{eq name='mod' value='0'}...
- 通过编译文件可以理解,
mod=2
表示索引除以2得到的余数是否等于0或1; - 如果余数设置为0,那么输出的即偶数,如果设置为1,则输出的是奇数;
- 当然,切换到其它数字,也会有更多的排列效果;
- 使用
empty
属性,可以当没有任何数据的时候,实现输出指定的提示;
{volist name="list" id="obj" empty="没有数据"}
- 使用
key='k'
,让索引从1开始计算,不指定就用{$i}
,指定后失效;
{volist name='list' id='obj' key='k'}
{$k}
{/volist}
for循环
for
循环,顾名思义,通过起始和终止值,结合步长实现的循环;
{for start='1' end='100' comparison='lt' step='2' name='i'}
{$i}
{/for}
模版的比较和定义标签
比较标签
{eq}..{/eq}
标签,比较两个值是否相同,相同即输出包含内容;
{eq name='name' value='Mr.Lee'}
李先生
{/eq}
- 属性
name
里是一个变量,$符号可加可不加;而value
里是一个字符串; - 如果
value
也需要是一个变量的话,那么value
需要加上$后的变量;
{eq name='name2' value='$name2'}
- 这一组标签也支持
else
操作,标签为:{else/}
;
{eq name='name' value='Mr.Lee'}
两个值相等
{else/}
两个值不等
{/eq}
{eq}
标签有一个别名标签:{equal}
,效果是一样的,所有比较标签如下;
- 所有的标签都可以统一为
{compare}
标签使用,增加一个type
方法指定即可;
{compare name='name' value='Mr.Lee' type='eq'}两个值相等{/compare}
定义标签
- 如果你想在模版文件中去定义一个变量,可以使用
{assgin}
标签;
{assign name='var' value='123'} <!-- //也支持变量 value='$name' -->
{$var}
- 有变量的定义就会有常量的定义,可以使用
{define}
标签;
{define name='PI' value='3.1415'}
{$Think.const.PI}
- 有时,实在不知道在模版中怎么进行编码时,可以采用
{php}
标签进行原生编码;
{php}
echo '原生编码防止脱发';
{/php}
- 要注意的是:原生编码就是PHP编码,不能再使用模版引擎的特殊编码方式;
- 比如
{eq}
,{$user.name}
这些标签语法均不支持; - 标签之间,是支持嵌套功能的,比如从列表中找到
樱桃小丸子
;
{foreach $list as $key=>$obj}
{eq name='obj->username' value='樱桃小丸子'}
...
{/eq}
{/foreach}
模版的条件判断标签
switch标签
- 使用{switch}...{/switch}可以实现多个条件判断;
{switch number}
{case 1}1{/case}
{case 5}5{/case}
{case 10}10{/case}
{default/}不存在
{/switch}
- {case}也支持多个条件判断,使用
|
线隔开即可;
{case 10|20|30}10,20,30 均可{/case}
- {case}后面也可以是变量,设置变量后不可以使用
|
线;
{case $id}
if标签
- 使用简单条件判断的
{if}
标签;
{if $number > 10}大于 10{/if}
{if}
标签的条件判断可以使用AND
,OR
等语法;
{if ($number > 10) OR ($number > 5)}大于 10{/if}
{if}
标签支持{else/}
语法;
{if $number > 10}
大于 10
{else/}
小于 10
{/if}
{if}
标签也支持{elseif}
多重条件判断;
{if $number > 100}
大于 100
{elseif $number > 50}
大于 50
{else}
小于 50
{/if}
{if}
标签中的条件判断支持PHP写法,比如函数和对象调用;
{if strtoupper($user->name) == 'MR.LEE'}
1997sty
{/if}
范围标签
- 范围标签:
{in}
和{notin}
,判断值是否存在或不存在指定的数据列表中;
{in name='number' value='10,20,30,40,50'}存在{/in}
{in name='number' value='10,20,30,40,50'}
存在数据列表中
{else/}
不存在数据列表中
{/in}
name
值可以是是系统变量,比如$Think.xxx.yyy
,value
可以是变量;- 范围标签:
{between}
和{notbetween}
,判断值是否存在或不存在数据区间中;
{between name='number' value='10,50'}存在{/between}
{between name='number' value='10,50'}
存在数据区间中
{else/}
不存在数据区间中
{/between}
between
中的value
只能是两个值,表示一个区间,第三个值会无效;- 区间不但可以表达数字,也可以是字母,比如a-z,A-Z;
是否存在标签
- 是否存在:
{present}
和{notpresent}
判断变量是否已经定义赋值(是否存在);
{present name='user'}存在{/present}
{present name='user'}
user 已存在
{else/}
user 不存在
{/present}
- 是否为空:
{empty}
和{notempty}
判断变量是否为空值;
{empty name='username'}有值{/empty}
{empty name='username'}
username 有值
{else/}
username 没值
{/empty}
- 常量是否定义:
{defined}
和{notdefined}
判断常量是否定义(是否存在);
{defined name='PI'}
PI 存在
{else/}
PI 不存在
{/defined}
模版的加载包含输出
包含文件
- 使用
{include}
标签来加载公用重复的文件,比如头部,尾部和导航部分; - 在模版
view
目录创建一个public
公共目录,分别创建header
,footer
和nav
; - 然后创建控制器,引入控制器模版
index
,这个模版包含三个公用文件;
{include file='public/header,public/nav'/}
- 也可以包含一个文件的完整路径,包括后缀,如下:
{include file="../view/public/nav.html"/}
- 模版的标题和关键字,可以通过固定的语法进行传递;
- 对于标题,在控制器先设置一下标题变量,然后设置
{include}
设置属性;
{include file='public/header' title='$title' keywords='关键字'/}
- 切换到
public/header.html
模版页面,使用[xxx]
的方式调用数据;
<title>[title]</title>
<meta name="keywords" content="[keywords]" />
输出替换
- 有时,我们需要调用一些静态文件,比如
css/js
等; - 那么,直接写完整路径,比较繁长,可以把这些路径整理打包;
- 在目前二级目录下,
view.php
中,配置新增一个参数;
// 模版替换输出
'tpl_replace_string' => [
'__JS__' => '../static/js',
'__CSS__' => '../static/css',
],
- html 文件调用端,直接通过
__CSS__(__JS__)
配置的魔术方法调用即可;
<link rel="stylesheet" type="text/css" href="__CSS__/css.css">
<script type="text/javascript" src="__JS__/js.js"></script>
- 在测试的时候,由于是更改的配置文件刷新,每次都要删除编译文件才能生效;
文件加载
- 传统方式调用
CSS
或JS
文件时,采用link
和script
标签实现; - 系统提供了更加智能的加载方式,方便加载CSS和JS等文件;
- 使用
{load}
标签和href
属性来链接,不需要设置任何其它参数;
{load href='__CSS__/css.css'/}
{load href='__JS__/js.js'/}
- 也支持
href
多属性值的写法,如下:
{load href='__CSS__/css.css, __JS__/js.js'}
{load}
还提供了两个别名{js}
,{css}
来更好的实现可读性;
{js href='__JS__/js.js'}
{css href='__CSS__/css.css'}
{js}
和{css}
只是别名而已,识别.js
还是.css
是根据后缀的;
模版的布局和继承
模版布局
- 默认情况下,不支持模版布局功能,需要在配置文件中开启;
- 在配置文件
view.php
中,配置开始模版布局功能;
'layout_on' => true,
- 此时,执行上一节课的模版控制器,会发现提示缺少模版
layout.html
; - 这个默认的布局文件,是可以更改的,位置和名字均可配置;
'layout_name' => 'public/layout',
layout.html
负责所有通用模块的代码部分,而局部内容通过变量引入;- 使用
{__CONTENT__}
类似魔术方法的标签来引入index.html
非通用内容;
{include file='public/header,public/nav' title='$title' keywords='关键字!'/}
{__CONTENT__}
- 你可以更改
{__CONTENT__}
,只要在配置文件中配置;
'layout_item' => '{__REPLACE__}',
- 再强调:再测试的时候,如果更改了配置文件,务必删除
temp
下编译文件再刷新; - 上面说的是第一种,配置文件下来开启布局,而第二种方式则不需要开启直接使用;
- 首先,你必须关闭第一种配置,我这里就直接注释掉了,然后使用
{layout}
标签; - 只要在
block.html
的最上面加上如下代码,即可实现模版布局;
{layout name="public/layout"}
模版继承
- 模版继承是另一种布局方式,这种布局的思路更加的灵活;
- 首先,我们要创建一个
public/base.html
的基模版文件,文件名随意;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{$title}</title>
</head>
<body>
</body>
</html>
- 创建一个新的方法
extend
载入新的模版extend.html
,然后加载基模版;
{extend name='public/base'}
{extend name='../app/view/public/base.html'}
- 在基模版
base.html
中,设置几个可替换的区块部分,{block}
标签实现;
{block name='nav'}{include file='public/nav'}{/block}
{block name='footer'} @ThinkPHP 版权所有 {/block}
- 在
base.html
中,{include}
可以加载内容,而在extend.html
可以改变加载;
{block name='nav'}替换内容{/block}
- 替换前
- 替换后
模版的杂项和表单令牌
模版的杂项
- 有时,我们需要输出类似模版标签或语法的数据,这时会被模版解析;
- 此时,我们就使用模版的原样输出标签
{literal}
;
{literal}
变量标签形式:{$name}
{/literal}
- 对于在HTML页面中的标签,用HTML注释是无效的,需要模版定义的注释;
{//$name}
{/*$name*/}
{/* 多行注释
*/}
- 注释和
{
符号之间不能有空格,否则无法实现注释隐藏; - 生成编译文件后,注释的内容会自动被删除,不会显示;
表单令牌
- 表单令牌就是在表单中增加一个隐藏字段,随机生成一串字符,确定不是伪造;
- 这种随机产生的字符和服务器的
session
(开启)进行对比,通过则是合法表单;
<form action="/show/token" method="post">
<input type="hidden" name="__token__" value="{:token()}">
<input type="submit" value="提交表单">
</form>
- 为了验证系统内部的机制,可以通过打印测试出内部的构造;
//打印出保存到 session 的 token
echo Session::get('__token__');
- 在验证端口,可以使用控制器验证单独验证
token
是否验证成功;
$check = Request::checkToken('__token__');
if(false === $check) {
throw new ValidateException('令牌错误');
}
- 验证器部分,只要使用内置规则
token
即可验证,具体流程如下:
$validate = \think\facade\Validate::rule([
'name' => 'require|token'
]);
$result = $validate->batch(true)->check([
'name' => input('post.name'),
'__token__' => input('post.__token__')
]);
if (!$result) {
dump($validate->getError());
}
最后一次更新于2020-08-05 17:01
0 条评论