# 主题 <p class="uk-article-lead">主题改变网站的外观。主题最简单的形式就是在生成一系列的 HTML 标签来包裹由各种扩展输出的内容。</p> **Note** 本教程中的例子来源于 _Hello_ 主题,可以在商店中安装它。安装后,_Hello_ 主题位于 `/packages/pagekit/theme-hello`. [toc=2] ## 包的定义 主题其实是 Pagekit 的 `pagekit-theme` 类型的[包](224130)。每个包都需要一个描述让 Pagekit 识别它。描述是位于 `composer.json` 文件中,看起来是下面代码的样子。 更多详情,查阅[包](224130) 这一章。 ```json { "name": "pagekit/theme-hello", "type": "pagekit-theme", "version": "0.9.0", "title": "Hello" } ``` ## 模块的定义 主题本身只是一个[模块](224131)。所以你可能想要先去阅读模块。它为主题能做的事展开了许多可能性。 定义主题中的控件位置和菜单,加载额外的脚本等等。这里有一个简短的 `index.php` 例子可以让你快速起步。主题具体的属性解释都在下文中。 ```php return [ 'name' => 'theme-hello', /** * Define menu positions. */ 'menus' => [ 'main' => 'Main', ], /** * Define widget positions. */ 'positions' => [ 'sidebar' => 'Sidebar', ] ]; ``` 主题定义渲染菜单和小工具的位置。如下面的说明,实际的渲染发生在 `template.php` 中。然而,你的主题需要先注册这些位置,需要用到 `menus` 和 `positions` 属性。这些包含位置名称和标签的数组,会显示在管理面板中。 ### 菜单 在主题中,可以在从 Pagekit 系统中渲染随意多个菜单到各个位置上。要让 Pagekit 知晓这些位置,需要使用 `menu` 属性注册它们。 每个菜单位置都是由识别符(比如 `main`)和标签定义,并显示给用户(比如 _Main_)。 ```php 'menus' => [ 'main' => 'Main', 'offcanvas' => 'Offcanvas' ], ``` ### 位置 小工具位置允许用户将小工具发布到主题标签中的各个位置上。它们显示在 Pagekit 管理面板的 _Widgets_ 这块,可以设置小工具的时候进行选择。 每个小工具位置都是由识别符(比如 `sidebar`)和标签定义,并显示给用户(比如 _Sidebar_)。 ```php 'positions' => [ 'sidebar' => 'Sidebar', ], ``` ## 布局文件 除了强制性的模块文件,主题带有它自己的 `views/template.php` 文件。它是主题标签的主要文件,含有以下用于渲染的对象。 |对象 | 描述 | |--------- | ------------------------------ | |`$view` | 视图渲染器实例| |`$params` | 主题参数| |`$app` | Application 容器实例| **Note** 对于 PHP 模板,短码(short notation) `<?= $var ?>` 输出变量 `$var` 的值。 ```html <!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"> <!-- Always render head section from the system --> <?= $view->render('head') ?> <!-- Include theme css --> <?php $view->style('theme', 'theme:css/theme.css') ?> <!-- Include theme JS, require jQuery which will also be included --> <?php $view->script('theme', 'theme:js/theme.js', 'jquery') ?> </head> <body> <!-- Render logo with site URL --> <?php if ($logo = $params['logo']) : ?> <a href="<?= $view->url()->get() ?>"> <img src="<?= $this->escape($logo) ?>" alt=""> </a> <?php endif ?> <!-- Render menu position --> <?php if ($view->menu()->exists('main')) : ?> <?= $view->menu('main') ?> <?php endif ?> <!-- Render widget position --> <?php if ($view->position()->exists('sidebar')) : ?> <?= $view->position('sidebar') ?> <?php endif; ?> <!-- Render system messages --> <?= $view->render('messages') ?> <!-- Render content --> <?= $view->render('content') ?> <!-- Insert code before the closing body tag --> <?= $view->render('footer') ?> </body> </html> ``` ## 菜单和位置渲染器 你可能想要使用自定义菜单或位置渲染器。下面有两个例子想你展示如何使用它们。 ```php <?= $view->menu('main', 'menu-navbar.php') ?> ``` 此例中,`main` 菜单将被 `menu-navbar.php` 布局文件渲染。 ```php <ul class="uk-navbar-nav"> <?php foreach ($root->getChildren() as $node) : ?> <li> <!-- ... more markup ... --> </li> <?php endforeach ?> </ul> ``` 同样可用于小工具位置。 ```php <?= $view->position('hero', 'position-grid.php') ?> ``` 这里,小工具位置 `hero` 将被 `position-grid.php` l 布局文件渲染。 ```php <?php foreach ($widgets as $widget) : ?> <div class="uk-width-1-<?= count($widgets) ?>"> <div> <h3><?= $widget->title ?></h3> <?= $widget->get('result') ?> </div> </div> <?php endforeach ?> ``` ## 默认的 Pagekit 标签 Pagekit 的管理面板使用 UIkit 前端框架构建。这就是为何 Pagekit 的核心扩展,比如静态页面和博客,都会输出带有 UIkit 的 CSS class 的标签。所以,你完全可以使用 UIkit 来创建自己的主题。 要为 Pagekit 系统输出的信息添加样式,你可以只为少量 class 添加 CSS,而不是引入整个 UIkit CSS。Hello 主题的 `theme.css` 文件已经带有必要的 class了。 如果想要彻底修改 Pagekit 自己生成的标签,可以覆写系统的视图文件。 ## 覆写系统视图 要覆写系统的视图文件,只需要按下表所述,在主题中创建相应的文件夹来模拟原有的文件结构,并将主题文件放在此处。 |文件 | 原有视图文件 | 描述| |---------------------------- | ---------------------------------------- | ------------------------| |`views/system/site/page.php` | `/app/system/site/views/page.php` | 默认的静态页面视图| |`views/blog/post.php` | `/packages/pagekit/blog/views/post.php` | 博客文章单页视图| |`views/blog/posts.php` | `/packages/pagekit/blog/views/posts.php` | 博客文章列表视图| 要了解在这些视图中有哪些可用变量,可以在原有视图文件中找到。 ## 为网站界面添加主题选项 这是通过 javascript 实现的,如果使用 Vue 组件,会非常顺利。 在站点树界面已激活时,加载你的 JS。在 `index.php` 中,你可以监听响应的事件来进行此操作。 ``` 'events' => [ 'view.system/site/admin/settings' => function ($event, $view) use ($app) { $view->script('site-theme', 'theme:js/site-theme.js', 'site-settings'); $view->data('$theme', $this); }, // ... ], ``` `js/site-theme.js` 包含渲染界面和负责存储主题设置的 Vue 组件。 **Note** 尽管可以在单个 JS 文件中处理这些东西,并以字符串表示标签,但事实上最佳实践是使用 Vue 组件创建 `*.vue` 文件。在默认的 _One_ 主题中的`app/components` 文件夹可以找到例子。 ```js window.Site.components['site-theme'] = { section: { label: 'Theme', icon: 'pk-icon-large-brush', priority: 15 }, template: '<div>Your form markup here</div>', data: function () { return window.$theme; }, events: { save: function() { var config = _.omit(this.config, ['positions', 'menus', 'widget']); this.$http.post('admin/system/settings/config', {name: this.name, config: config}).error(function (data) { this.$notify(data, 'danger'); }); } } }; ``` ## 为站点树中的节点配置添加主题选项卡 要为站点树中特定的节点(Node)添加主题选项。例如,想要允许用户为每个页面选取不同的主图。可以为站点界面添加一个 _Theme_ 选项卡。 ```php 'events' => [ // ... 'view.system/site/admin/edit' => function ($event, $view) { $view->script('node-theme', 'theme:js/node-theme.js', 'site-edit'); }, // ... ]; ``` 针对 `js/node-theme.js` 的例子: ```js window.Site.components['node-theme'] = { section: { label: 'Theme', priority: 90 }, props: ['node'], template: '<div>Your form markup here</div>' }; ``` **Note** 与默认的 _One_ 主题中 `app/components` 文件夹中完整的 Vue 组件进行比较。 ## 为小工具界面添加主题选项 注册要在_Widget_ 编辑视图中加载的脚本。 ``` 'view.system/widget/edit' => function ($event, $view) { $view->script('widget-theme', 'theme:app/bundle/widget-theme.js', 'widget-edit'); }, ``` Example for `widget-theme.js`: ```js window.Widgets.components['widget-theme'] = { section: { label: 'Theme', priority: 90 }, props: ['widget', 'config'], template: '<div>Your form markup here</div>' }; ``` **Note** 与默认的 _One_ 主题中 `app/components` 文件夹中完整的 Vue 组件进行比较。 ## 手动添加设置页面 如果预设的添加设置页面的方法不符合你的需要,你还可以手动创建全新的界面。使用 `index.php` 中的模块定义,你能掌控一切然后可以像下面这样来处理: 1. 为设置页面创建视图文件 2. 新建一个包含渲染此视图文件的操作的控制器 3. 在 `index.php` 中注册控制器和路由 4. 可选,将 `settings` 设为新的设置页面的路径