# 视图 & 模板
<p class="uk-article-lead">控制器处理传入的请求时,视图负责渲染响应。为了实现这一点,它使用一个模板引擎。在Pagekit,您可以使用纯PHP模板或 twig 模板引擎。</p>
[toc=2]
## 已渲染的视图响应
渲染视图最常见的方式是从控制器操作中返回一个数组。使用 `$view` 属性将参数传到你的视图渲染器。
```php
public function indexAction($name = '')
{
return [
'$view' => [
// 在网站的 <title> 中渲染
'title' => 'Hello World',
//已渲染的视图文件
'name' => 'hello:views/index.php',
],
// 传递参数到视图文件
'name' => $name
];
}
```
已渲染的视图文件看起来是这样:
```php
<!-- packages/pagekit/extension-hello/views/index.php -->
<h1>Hello <?= $name ?></h1>
<p>
...
</p>
```
这个视图默认包裹在主要布局(main layout)中。要避免此行为,你可以在 `$view` 数组中修改 `'layout' => false`。
## 手动渲染视图
可以手动访问 `View` 服务来渲染模板文件。这会在动态判断加载哪些视图时派上用场。注意,在下面的例子中 `hello:` 指的是使用 [模块](224131)中的源码简写方法定义的简写。。
```php
use Pagekit\Application as App;
class MyController {
public function anotherViewAction()
{
return App::view()->render('hello:views/view.php', ['id' => 1]);
}
}
```
相关视图文件:
```HTML
<!-- packages/pagekit/extension-hello/views/index.php -->
<h1>You are viewing article number <?= $id ?></h1>
<p>
...
</p>
```
## Templating
这些视图是使用 PHP 模板引擎渲染的,模板引擎提供了已定义的全局模板变量和一系列视图助手。
### 引入其他视图
使用 `$view`助手在视图中渲染子视图。 `render` 方法评估并返回模板文件的内容。这与在控制器中手动渲染视图是相同的。
```php
$view->render('hello:views/view.php', ['id' => 1])
```
### 链接到路由
正如前面看到的,每个路径都有一个名称,你可以动态生成链接到具体路线的链接。`Url`暴露了 `UrlProvider`的功能。
```HTML
<a href="<?= $view->url('@hello/default/view') ?>">View all articles</a>
<a href="<?= $view->url('@hello/default/view', ['id' => 23]) ?>">View article 23</a>
```
可以链接到资源,比如图片或其他文件,使用 URL 提供者(`UrlProvider`)的 `getStatic($path)` 方法。
```HTML
<img src="<?= $view->url()->getStatic('hello:extension.svg') ?>" alt="Extension icon" />
```
## 处理资源/Assets
资源是指项目中需要的静态文件,包括CSS、JS和图片文件等。
### 生成静态资源的 URL
要生成静态资源的路由,使用`UrlProvider` 类的 `getStatic` 方法。
```php
<img src="<?= $view->url()->getStatic('my-assets/image.jpg') ?>">
```
### 在视图文件中引入 CSS
在视图文件中引入 CSS,调用 `View` 中的 `style` 助手。
```php
$view->style($id, $path [, $dependencies ])
```
第一个参数是样式表的唯一标识符。如果为多个样式表使用同一个标识符,Pagekit只会引入最后一个。第二个参数是样式表的路径,可以使用 `theme:` 作为 'theme'包根目录的参照。可以通过可选的第三个参数定义依赖。
Example:
```
<?php $view->style('theme', 'theme:css/theme.css') ?>
<?php $view->style('theme', 'theme:css/theme.css', 'uikit') ?>
<?php $view->style('theme', 'theme:css/theme.css', ['uikit', 'somethingelse']) ?>
```
**Note** 这并不会直接在 HTML 中输出,它会将 CSS 文件添加到 Pagekit 的资源管理器(Pagekit Asset Manager)。样式表会引入到主题的 `<head>` 部分。
### 在视图文件中引入 JS
要在模板中引入 javascript 文件,调用 `#view` 对象的 `script` 助手,作用和 `style` 助手一样。
```php
$view->script($id, $path [, $dependencies ])
```
第一个参数是脚本资源的唯一标识符。如果为多个脚本使用了相同的标识符,Pagekit 只会引入最后一个。第二个参数是脚本的路径,可以使用 `theme:` 作为 'theme'包根目录的参考。可以通过可选的第三个参数定义依赖。
Example:
```
<?php $view->script('theme', 'theme:js/theme.js') ?>
<?php $view->script('theme', 'theme:js/theme.js', 'jquery') ?>
<?php $view->script('theme', 'theme:js/theme.js', ['jquery', 'uikit']) ?>
```
**Note** 在内部,`style()` 和 `script()` 各自使用它们自己的资源管理器。这些都是彼此分开的,可以无冲突地为 CSS 和 JS 文件指定相同的名称(前面的例子里都叫做 `theme`)。然而,两个脚本或样式表不能使用相同的名称。例如,在添加两个样式表时,一个可以称为 'theme',另一个称为 'custom'。
### 异步和延迟脚本执行/Async and deferred script execution
默认地,脚本会在已渲染的 HTML 标签的 head 部分被引入,是即时获取并执行的。之后,浏览器才会继续解析页面。
要改变这样的行为,可以在加载脚本时使用关键字 `async` 和 `defer`。在 PHP 代码中设置适当的选项,于是在最后的 `<script>` 标签中将会有这些属性。
|属性 | 描述|
|--------- | -----------|
|`async` | 告诉浏览器异步执行脚本,这意味着就算是在执行脚本,页面解析也会继续。|
|`defer` | 告诉浏览器在页面解析完毕后再执行脚本。浏览器对于这个 HTML 特性的支持并不完美,只是会在脚本执行的顺序很重要时使用它才会导致一些问题。|
Example: 延迟执行,无依赖。
```
<?php $view->script('theme', 'theme:js/theme.js', [], ['defer']) ?>
```
Example: 有依赖的延迟和异步执行。
```
<?php $view->script('theme', 'theme:js/theme.js', ['jquery', 'uikit'], ['defer', 'async']) ?>
```
## Twig 模板
可以在主题和扩展模板中使用 Twig 来替代原生的 PHP 模板。在 Twig 官方文档的基础[Twig 语法和特性](http://twig.sensiolabs.org/doc/templates.html) 上找到相关资料。类似于官方使用默认的PHP模板制作的的 Hello 主题,还有一个 [boilerplate Twig theme](https://github.com/florianletsch/theme-twig) ,可以用它作为起点。
### 使用 Twig 构建主题
默认地,Pagekit 主题用到的主要模板文件,位于 `views/template.php`,并且它是使用默认的 PHP 渲染器进行渲染的。在主题的 `index.php` 中,你可以另外定义一个布局文件用作主要模板。
```
/**
* 使用 Twig 模板修改默认布局
*/
'layout' => 'views:template.twig',
```
文件扩展名 `*.twig` 将导致 Pagekit 使用 Twig 引擎来渲染模板。主题的 `views/template.twig` 的简单例子,看起来是这样:
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{ view.render('head') | raw }}
{{ view.style('theme', 'theme:css/theme.css') }}
{{ view.script('theme', 'theme:js/theme.js') }}
</head>
<body>
<!-- Render logo or title with site URL -->
<a href="{{ view.url().get() }}">
{% set logo = params.logo %}
{% if logo %}
<img src="{{ logo }}" alt="Logo">
{% else %}
{{ params.title }}
{% endif %}
</a>
<!-- Render menu position -->
{% if view.menu().exists('main') %}
{{ view.menu('main') | raw }}
{% endif %}
<!-- Render widget position -->
{% if view.position().exists('sidebar') %}
{{ view.position('sidebar') | raw }}
{% endif %}
<!-- Render system messages -->
{{ view.render('messages') | raw }}
<!-- Render content -->
{{ view.render('content') | raw }}
<!-- Insert code before the closing body tag -->
{{ view.render('footer') | raw }}
</body>
</html>
```
如你所见,可以为输出的已转义内容使用基础的 Twig 语法(`{{ ... }}`),未转义内容使用 (`{{ ... | raw }}`)。默认的控制结构,比如 `if` 和 `for` 都是可用的,更多详情查阅[Twig 语法](http://twig.sensiolabs.org/doc/templates.html) 文档。
Pagekit 的视图助手和函数通过可以在模板中用作 `view` 的视图渲染器暴露。PHP 表达式可以轻松转换为 Twig 语法,例如为当前页面添加 CSS 文件:
```html
<!-- PHP version -->
<?php $view->style('theme', 'theme:css/theme.css'); ?>
<!-- Twig version -->
{{ view.style('theme', 'theme:css/theme.css') }}
```