Html 帮助类
任何一个 web 应用程序会生成很多 HTMl 超文本标记。如果超文本标记是静态的,那么将 PHP 和 HTML 混合在一个文件里这种做法是非常高效的。但是,如果这些超文本标记是动态生成的,那么如果没有额外的辅助工具,这个过程将会变得复杂。Yii 通过 HTML 帮助类来提供生成超文本标记的方法。这个帮助类包含有一系列的用于处理通用的 HTML 标签和其属性以及内容的静态方法。
注意:如果你的超文本标记接近静态的,那么最好是直接使用 HTML。没有必要把所有的超文本标记都用 HTML 辅助类来生成。
基础
由于通过字符串连接来生成动态的 HTML 会很容易变得凌乱,Yii 提供了一系列的静态方法来操作标签配置并基于这些配置来创建对应的标签。
生成标签
生成一个标签的代码类似如下:
= Html::tag('p', Html::encode($user->name), ['class' => 'username']) ?>
这个方法的第一个参数是标签名称。第二个是要装入到开始和结束标签间的内容。注意到我们使用 Html::encode
。那是因为内容不会被自动的转码以允许在有需要的时候嵌套 HTML。第三个参数是一个 HTML 配置数组,或者换言之,标签属性。在这个数组中,数组的下标是属性名称,比如class
,href
或者 target
,而值则是对应属性的值。
以上代码会生成如下 HTML :
<p class="username">samdarkp>
如果你只需要开启一个标签或者关闭一个标签,你可以使用 Html::beginTag()
和 Html::endTag()
方法。
标签属性( Options )在 Html 帮助类很多方法和大量的小部件中都有使用。在这些情况下,有一些额外的处理我们需要知道:
- 如果一个值为 null ,那么对应的属性将不会被渲染。
- 如果是布尔类型的值的属性,将会被当做 布尔属性 来处理。
- 属性的值将会用 yii\helpers\Html::encode() 方法进行 HTML 转码处理。
-
如果一个属性的值是一个数组,那么它将会被如下处理:
- 如果这个属性是一个如 yii\helpers\Html::$dataAttributes 所列的数据属性,比如
data
或者ng
,一系列的属性列表将会被渲染,每个代表值数组中的元素。比如:'data' => ['id' => 1, 'name' => 'yii']
将会生成data-id="1" data-name="yii"
;'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']
生成data-params='{"id":1,"name":"yii"}' data-status="ok"
。注意后者 中,一个子数组被输出为 JSON 。 - 如果这个属性不是一个数据属性,那么值将会被 JSON-encoded。比如:
['params' => ['id' => 1, 'name' => 'yii']
生成params='{"id":1,"name":"yii"}'
。
- 如果这个属性是一个如 yii\helpers\Html::$dataAttributes 所列的数据属性,比如
生成 CSS 类和样式
当开始构造一个 HTML 标签的属性时,我们经常需要对默认的属性进行修改。为了添加或者删除 CSS 类,你可以使用如下代码:
$options = ['class' => 'btn btn-default'];
if ($type === 'success') {
Html::removeCssClass($options, 'btn-default');
Html::addCssClass($options, 'btn-success');
}
echo Html::tag('div', 'Pwede na', $options);
// in case of $type of 'success' it will render
// Pwede na
基于同样的目的,针对 style
属性:
$options = ['class' => ['btn', 'btn-default']];
echo Html::tag('div', 'Save', $options);
// renders 'Save'
While adding or removing classes you may use the array format as well:
$options = ['class' => 'btn'];
if ($type === 'success') {
Html::addCssClass($options, ['btn-success', 'btn-lg']);
}
echo Html::tag('div', 'Save', $options);
// renders 'Save'
Html::addCssClass()
prevents duplicating classes, so you don't need to worry that the same class may appear twice:
$options = ['class' => 'btn btn-default'];
Html::addCssClass($options, 'btn-default'); // class 'btn-default' is already present
echo Html::tag('div', 'Save', $options);
// renders 'Save'
If the CSS class option is specified via the array format, you may use a named key to mark the logical purpose of the class.In this case, a class with the same key in the array format will be ignored inHtml::addCssClass()
:
$options = [
'class' => [
'btn',
'theme' => 'btn-default',
]
];
Html::addCssClass($options, ['theme' => 'btn-success']); // 'theme' key is already taken
echo Html::tag('div', 'Save', $options);
// renders 'Save'
CSS styles can be setup in similar way using style
attribute:
$options = ['style' => ['width' => '100px', 'height' => '100px']];
// gives style="width: 100px; height: 200px; position: absolute;"
Html::addCssStyle($options, 'height: 200px; position: absolute;');
// gives style="position: absolute;"
Html::removeCssStyle($options, ['width', 'height']);
当使用 yii\helpers\Html::addCssStyle() 方法时,你可以指定一个和 CSS 属性相关的名值对的数组,也可以直接是一个类似 width: 100px; height: 200px;
的字符串。这些格式将会自动的被 yii\helpers\Html::cssStyleFromArray() 和yii\helpers\Html::cssStyleToArray() 方法进行转换。方法 yii\helpers\Html::removeCssStyle() 接收一个包含要被移除的属性数组作为参数。如果只想移除一个属性,你可以直接传递一个字符串。
标签内容的转码和解码
为了让内容能够正确安全的显示,一些 HTML 特殊字符应该被转码。在 PHP 中,这个操作由 htmlspecialchars 和htmlspecialchars_decode 完成。直接使用这些方法的问题是,你总是需要指定转码所需的额外标志。由于标志一般总是不变的,而内容转码的过程为了避免一些安全问题,需要和应用的默认过程匹配,Yii 提供了两个简单可用的对 PHP 原生方法的封装:
$userName = Html::encode($user->name);
echo $userName;
$decodedUserName = Html::decode($userName);
表单
处理表单标签是大量的重复性劳动并且易错。因此,Yii 也提供了一系列的方法来辅助处理表单标签。
注意: 考虑在处理 models 以及需要验证的情形下,使用 yii\widgets\ActiveForm 组件。
创建表单
表单可以用类似如下代码,使用 yii\helpers\Html::beginForm() 方法开启:
= Html::beginForm(['order/update', 'id' => $id], 'post', ['enctype' => 'multipart/form-data']) ?>
方法的第一个参数为表单将要被提交的 URL 地址。它可以以 Yii 路由的形式被指定,并由 yii\helpers\Url::to() 来接收处理。第二个参数是使用的方法,默认为post
方法。第三个参数为表单标签的属性数组。在上面的例子中,我们把编码 POST 请求中的表单数据的方式改为 multipart/form-data
。如果是上传文件,这个调整是必须的。
关闭表单标签非常简单:
= Html::endForm() ?>
按钮
你可以用如下代码生成按钮:
= Html::button('Press me!', ['class' => 'teaser']) ?>
= Html::submitButton('Submit', ['class' => 'submit']) ?>
= Html::resetButton('Reset', ['class' => 'reset']) ?>
上述三个方法的第一个参数为按钮的标题,第二个是标签属性。标题默认没有进行转码,如果标题是由终端用输入的,那么请自行用 yii\helpers\Html::encode() 方法进行转码。
输入栏
input 相关的方法有两组:以 active
开头的被称为 active inputs,另一组则不以其开头。active inputs 依据指定的模型和属性获取数据,而普通 input 则是直接指定数据。
一般用法如下:
type, input name, input value, options
= Html::input('text', 'username', $user->name, ['class' => $username]) ?>
type, model, model attribute name, options
= Html::activeInput('text', $user, 'name', ['class' => $username]) ?>
如果你知道 input 类型,更方便的做法是使用以下快捷方法:
- yii\helpers\Html::buttonInput()
- yii\helpers\Html::submitInput()
- yii\helpers\Html::resetInput()
- yii\helpers\Html::textInput(), yii\helpers\Html::activeTextInput()
- yii\helpers\Html::hiddenInput(), yii\helpers\Html::activeHiddenInput()
- yii\helpers\Html::passwordInput() / yii\helpers\Html::activePasswordInput()
- yii\helpers\Html::fileInput(), yii\helpers\Html::activeFileInput()
- yii\helpers\Html::textarea(), yii\helpers\Html::activeTextarea()
Radios 和 checkboxes 在方法的声明上有一点点不同:
= Html::radio('agree', true, ['label' => 'I agree']);
= Html::activeRadio($model, 'agree', ['class' => 'agreement'])
= Html::checkbox('agree', true, ['label' => 'I agree']);
= Html::activeCheckbox($model, 'agree', ['class' => 'agreement'])
Dropdown list 和 list box 将会如下渲染:
= Html::dropDownList('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
= Html::activeDropDownList($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
= Html::listBox('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
= Html::activeListBox($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
第一个参数是 input 的名称,第二个是当前选中的值,第三个则是一个下标为列表值,值为列表标签的名值对数组。
如果你需要使用多项选择, checkbox list 应该能够符合你的需求:
= Html::checkboxList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
= Html::activeCheckboxList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
否则,用 radio list :
= Html::radioList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
= Html::activeRadioList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
Labels 和 Errors
如同 inputs 一样,Yii 也提供了两个方法用于生成表单 label 。带 ative 方法用于从 model 中取数据,另外一个则是直接接收数据。
= Html::label('User name', 'username', ['class' => 'label username']) ?>
= Html::activeLabel($user, 'username', ['class' => 'label username'])
为了从一个或者一组 model 中显示表单的概要错误,你可以使用如下方法:
= Html::errorSummary($posts, ['class' => 'errors']) ?>
为了显示单个错误:
= Html::error($post, 'title', ['class' => 'error']) ?>
Input 的名和值
Yii 提供了方法用于从 model 中获取 input 的名称,ids,值。这些主要用于内部调用,但是有时候你也需要使用它们:
// Post[title]
echo Html::getInputName($post, 'title');
// post-title
echo Html::getInputId($post, 'title');
// my first post
echo Html::getAttributeValue($post, 'title');
// $post->authors[0]
echo Html::getAttributeValue($post, '[0]authors[0]');
在上面的例子中,第一个参数为模型,而第二个参数是属性表达式。在最简单的表单中,这个属性表达式就是属性名称,但是在一些多行输入的时候,它也可以是属性名以数组下标前缀或者后缀(也可能是同时)。
[0]content
代表多行输入时第一个 model 的 content 属性的数据值。dates[0]
代表 dates 属性的第一个数组元素。[0]dates[0]
代表多行输入时第一个 model 的 dates 属性的第一个数组元素。
为了获取一个没有前缀或者后缀的属性名称,我们可以如下做:
// dates
echo Html::getAttributeName('dates[0]');
样式表和脚本
Yii 提供两个方法用于生成包含内联样式和脚本代码的标签。
= Html::style('.danger { color: #f00; }') ?>
Gives you
= Html::script('alert("Hello!");', ['defer' => true]);
Gives you
如果你想要外联 css 样式文件,可以如下做:
= Html::cssFile('@web/css/ie5.css', ['condition' => 'IE 5']) ?>
generates
第一个参数是 URL。第二个参数是标签属性数组。比普通的标签配置项额外多出的是,你可以指定:
condition
来让被条件控制注释包裹( IE hacker )。希望你在未来不再需要条件控制注释。
noscript
可以被设置为true
,这样就会被
为了外联 JavaScript 文件:
= Html::jsFile('@web/js/main.js') ?>
这个方法的第一个参数同 CSS 一样用于指定外联链接。第二个参数是一个标签属性数组。同 cssFile
一样,你可以指定 condtion
配置项。
超链接
有一个方法可以用于便捷的生成超链接:
= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>
第一个参数是超链接的标题。它不会被转码,所以如果是用户输入数据,你需要使用 Html::encode()
方法进行转码。第二个参数是 标签的
href
属性的值。关于该参数能够接受的更详细的数据值,请参阅 Url::to()。第三个参数是标签的属性数组。
在需要的时候,你可以用如下代码生成 mailto
链接:
= Html::mailto('Contact us', 'admin@example.com') ?>
图片
为了生成图片标签,你可以如下做:
= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>
generates
"/docs/guide/2.0/http://example.com/images/logo.png" alt="My logo" />
除了 aliases 之外,第一个参数可以接受 路由,查询,URLs。同 Url::to() 一样。
列表
无序列表可以如下生成:
= Html::ul($posts, ['item' => function($item, $index) {
return Html::tag(
'li',
$this->render('post', ['item' => $item]),
['class' => 'post']
);
}]) ?>
有序列表请使用 Html::ol()
方法。
Url 帮助类
Url 帮助类提供一系列的静态方法来帮助管理 URL。
获得通用 URL
有两种获取通用 URLS 的方法 :当前请求的 home URL 和 base URL 。为了获取 home URL ,使用如下代码:
$relativeHomeUrl = Url::home();
$absoluteHomeUrl = Url::home(true);
$httpsAbsoluteHomeUrl = Url::home('https');
如果没有传任何参数,这个方法将会生成相对 URL 。你可以传 true
来获得一个针对当前协议的绝对 URL;或者,你可以明确的指定具体的协议类型( https
, http
)。
如下代码可以获得当前请求的 base URL:
`
php$relativeBaseUrl = Url::base();$absoluteBaseUrl = Url::base(true);$httpsAbsoluteBaseUrl = Url::base('https');
这个方法的调用方式和 `Url::home()` 的完全一样。
## 创建 URLs "creating-urls">
为了创建一个给定路由的 URL 地址,请使用 `Url::toRoute()`方法。 这个方法使用 \yii\web\UrlManager
来创建一个 URL :
```php
$url = Url::toRoute(['product/view', 'id' => 42]);
你可以指定一个字符串来作为路由,如: site/index
。如果想要指定将要被创建的 URL 的附加查询参数,你同样可以使用一个数组来作为路由。数组的格式须为:
// generates: /index.php?r=site/index¶m1=value1¶m2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
如果你想要创建一个带有 anchor 的 URL ,你可以使用一个带有 #
参数的数组。比如:
// generates: /index.php?r=site/index¶m1=value1#name
['site/index', 'param1' => 'value1', '#' => 'name']
一个路由既可能是绝对的又可能是相对的。一个绝对的路由以前导斜杠开头(如: /site/index
),而一个相对的路由则没有(比如: site/index
或者 index
)。一个相对的路由将会按照如下规则转换为绝对路由:
- 如果这个路由是一个空的字符串,将会使用当前 \yii\web\Controller::route 作为路由;
- 如果这个路由不带任何斜杠(比如
index
),它会被认为是当前控制器的一个 action ID,然后将会把 \yii\web\Controller::uniqueId 插入到路由前面。 - 如果这个路由不带前导斜杠(比如:
site/index
),它会被认为是相对当前模块(module)的路由,然后将会把 \yii\base\Module::uniqueId 插入到路由前面。
从2.0.2版本开始,你可以用 alias 来指定一个路由。在这种情况下, alias 将会首先转换为实际的路由,然后会按照上述规则转换为绝对路由。
以下是该方法的一些例子:
// /index.php?r=site/index
echo Url::toRoute('site/index');
// /index.php?r=site/index&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// /index.php?r=post/edit&id=100 assume the alias "@postEdit" is defined as "post/edit"
echo Url::toRoute(['@postEdit', 'id' => 100]);
// http://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', true);
// https://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', 'https');
还有另外一个方法 Url::to()
和 toRoute() 非常类似。这两个方法的唯一区别在于,前者要求一个路由必须用数组来指定。如果传的参数为字符串,它将会被直接当做 URL 。
Url::to()
的第一个参数可以是:
- 数组:将会调用 toRoute() 来生成URL。比如:
['site/index']
,['post/index', 'page' => 2]
。详细用法请参考 toRoute() 。 - 带前导
@
的字符串:它将会被当做别名,对应的别名字符串将会返回。 - 空的字符串:当前请求的 URL 将会被返回;
- 普通的字符串:返回本身。
当 $scheme
指定了(无论是字符串还是 true ),一个带主机信息(通过 \yii\web\UrlManager::hostInfo 获得)的绝对 URL 将会被返回。如果 $url
已经是绝对 URL 了,它的协议信息将会被替换为指定的( https 或者 http )。
以下是一些使用示例:
// /index.php?r=site/index
echo Url::to(['site/index']);
// /index.php?r=site/index&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// /index.php?r=post/edit&id=100 assume the alias "@postEdit" is defined as "post/edit"
echo Url::to(['@postEdit', 'id' => 100]);
// the currently requested URL
echo Url::to();
// /images/logo.gif
echo Url::to('@web/images/logo.gif');
// images/logo.gif
echo Url::to('images/logo.gif');
// http://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', true);
// https://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', 'https');
从2.0.3版本开始,你可以使用 yii\helpers\Url::current() 来创建一个基于当前请求路由和 GET 参数的 URL。你可以通过传递一个 $params
给这个方法来添加或者删除 GET 参数。例如:
// assume $_GET = ['id' => 123, 'src' => 'google'], current route is "post/view"
// /index.php?r=post/view&id=123&src=google
echo Url::current();
// /index.php?r=post/view&id=123
echo Url::current(['src' => null]);
// /index.php?r=post/view&id=100&src=google
echo Url::current(['id' => 100]);
记住 URLs
有时,你需要记住一个 URL 并在后续的请求处理中使用它。你可以用以下方式达到这个目的:
// Remember current URL
Url::remember();
// Remember URL specified. See Url::to() for argument format.
Url::remember(['product/view', 'id' => 42]);
// Remember URL specified with a name given
Url::remember(['product/view', 'id' => 42], 'product');
在后续的请求处理中,可以用如下方式获得记住的 URL:
$url = Url::previous();
$productUrl = Url::previous('product');
检查相对 URLs
你可以用如下代码检测一个 URL 是否是相对的(比如,包含主机信息部分)。
$isRelative = Url::isRelative('test/it');