组件开发
Introduction
组件文件和目录位于/components 插件目录的子目录。每个组件都有一个定义组件类的 PHP 文件和一个可选的组件部分目录。组件部分目录名与小写的组件类名匹配。组件目录结构的示例:
📂 plugins
┗ 📂 acme
┗ 📂 myplugin
┣ 📂 components
┃ ┣ 📂 componentname <=== Component partials directory
┃ ┃ ┗ 📜 default.htm <=== Component default markup (optional)
┃ ┣ 📂 partials <=== Any partials shared by more than one component in the plugin
┃ ┃ ┗ 📜 partialname.htm
┃ ┗ 📜 ComponentName.php <=== Component class file
┗ 📜 Plugin.php
组件必须是在插件注册类中注册 与registerComponents
方法。
组件类定义
这组件类文件 定义组件功能和组件属性.组件类文件名应与组件类名匹配。组件类应该扩展\Cms\Classes\ComponentBase
班级。下一个示例中的组件应该在 plugins/acme/blog/components/BlogPosts.php 文件中定义。
namespace Acme\Blog\Components;
class BlogPosts extends \Cms\Classes\ComponentBase
{
public function componentDetails()
{
return [
'name' => 'Blog Posts',
'description' => 'Displays a collection of blog posts.'
];
}
// This array becomes available on the page as {{ component.posts }}
public function posts()
{
return ['First Post', 'Second Post', 'Third Post'];
}
}
这componentDetails
方法是必需的。该方法应返回一个包含两个键的数组:name
和description
.名称和描述显示在 CMS 后端用户界面中。
当这个组件附加到页面或布局,类属性和方法通过组件变量在页面上变得可用,该名称与组件短名称或别名相匹配。例如,如果上一个示例中的 BlogPost 组件是在一个页面上定义的,它的简称是:
url = "/blog"
[blogPosts]
==
您将能够访问其posts
方法通过blogPosts
多变的。请注意,Twig 支持方法的属性表示法,因此您无需使用方括号。
{% for post in blogPosts.posts %}
{{ post }}
{% endfor %}
组件注册
组件必须通过重写registerComponents
里面的方法插件注册类.这会告诉 CMS 有关该组件的信息并提供一个简称 使用它。注册组件的示例:
public function registerComponents()
{
return [
'Winter\Demo\Components\Todo' => 'demoTodo'
];
}
这将使用默认别名注册 Todo 组件类demoTodo.有关使用组件的更多信息,请访问CMS 组件文章.
组件属性
当您将组件添加到页面或布局时,您可以使用属性对其进行配置。属性定义为defineProperties
组件类的方法。下一个示例显示如何定义组件属性:
public function defineProperties()
{
return [
'maxItems' => [
'title' => 'Max items',
'description' => 'The most amount of todo items allowed',
'default' => 10,
'type' => 'string',
'validationPattern' => '^[0-9]+$',
'validationMessage' => 'The Max Items property can contain only numeric symbols'
]
];
}
该方法应返回一个数组,其中属性键作为索引,属性参数作为值。属性键用于访问组件类中的组件属性值。属性参数使用具有以下键的数组定义:
Key | Description |
---|---|
title |
required,属性标题,CMS后台组件Inspector使用。 |
description |
required,属性描述,CMS后台组件Inspector使用。 |
default |
可选,将组件添加到 CMS 后端的页面或布局时使用的默认属性值。 |
type |
可选,指定属性类型。类型定义属性在检查器中的显示方式。目前支持的类型有string ,checkbox ,dropdown 和set .默认值:string . |
validationPattern |
当用户在检查器中输入属性值时使用的可选正则表达式。验证只能与string 特性。 |
validationMessage |
如果验证失败,则显示可选的错误消息。 |
required |
可选,强制字段被填充。留空时使用 validationMessage。 |
placeholder |
字符串和下拉属性的可选占位符。 |
options |
下拉属性的可选选项数组。 |
depends |
下拉属性所依赖的属性名称数组。见下拉属性 以下。 |
group |
一个可选的组名。组在 Inspector 中创建部分以简化用户体验。在多个属性中使用相同的组名来组合它们。 |
showExternalParam |
指定检查器中属性的外部参数编辑器的可见性。默认值:true . |
在组件内部,您可以使用property
方法:
$this->property('maxItems');
如果未定义属性值,您可以提供默认值作为property
方法:
$this->property('maxItems', 6);
您还可以将所有属性加载为数组:
$properties = $this->getProperties();
要从组件的 Twig 部分访问属性,请使用__SELF__
引用 Component 对象的变量:
{{ __SELF__.property('maxItems') }}
下拉和设置属性
Adropdown
允许您从一系列选项中选择一个值。 Aset
允许您从一系列选项中选择多个值。
的选项列表dropdown
和set
属性可以是静态的或动态的。静态选项定义为options
下拉菜单的属性和items
集合的属性。例子:
public function defineProperties()
{
return [
'units' => [
'title' => 'Units',
'type' => 'dropdown',
'default' => 'imperial',
'placeholder' => 'Select units',
'options' => ['metric'=>'Metric', 'imperial'=>'Imperial']
],
'favoriteFruits' => [
'title' => 'Favorite fruits',
'type' => 'set',
'items' => [
'apples' => 'Apples',
'bananas' => 'Bananas',
'cantaloupes' => 'Cantaloupes',
],
'default' => ['bananas', 'cantaloupes'],
],
];
}
显示检查器时,可以从服务器动态获取选项或项目列表。如果options
下拉菜单或items
集合省略参数,列表被认为是动态的。组件类必须定义返回此列表的方法。该方法的名称应采用以下格式:get*Property*Options
, 在哪里Property 是属性名称,例如:getCountryOptions
.该方法返回一个选项数组,其中选项值作为键,选项标签作为值。动态下拉列表定义示例:
public function defineProperties()
{
return [
'country' => [
'title' => 'Country',
'type' => 'dropdown',
'default' => 'us'
]
];
}
public function getCountryOptions()
{
return ['us' => 'United states', 'ca' => 'Canada'];
}
动态的dropdown
和set
列表可以依赖于其他属性。例如,州列表可能取决于所选国家/地区。依赖项声明为depends
属性定义中的参数。下一个示例定义了两个动态下拉属性,州列表取决于国家/地区:
public function defineProperties()
{
return [
'country' => [
'title' => 'Country',
'type' => 'dropdown',
'default' => 'us'
],
'state' => [
'title' => 'State',
'type' => 'dropdown',
'default' => 'dc',
'depends' => ['country'],
'placeholder' => 'Select a state'
]
];
}
为了加载州列表,您应该知道当前在检查器中选择的是哪个国家/地区。 Inspector 将所有属性值发布到getPropertyOptions
处理程序,因此您可以执行以下操作:
public function getStateOptions()
{
$countryCode = Request::input('country'); // Load the country property value from POST
$states = [
'ca' => ['ab' => 'Alberta', 'bc' => 'British Columbia'],
'us' => ['al' => 'Alabama', 'ak' => 'Alaska'],
];
return $states[$countryCode];
}
页面列表属性
有时组件需要创建指向网站页面的链接。例如,博客文章列表包含指向博客文章详细信息页面的链接。在这种情况下,组件应该知道帖子详细信息页面文件名(然后它可以使用页面树枝过滤器). Winter 包含一个用于创建动态下拉页面列表的助手。下一个示例定义了显示页面列表的 postPage 属性:
public function defineProperties()
{
return [
'postPage' => [
'title' => 'Post page',
'type' => 'dropdown',
'default' => 'blog/post'
]
];
}
public function getPostPageOptions()
{
return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
}
路由参数
组件可以直接访问定义在页面的网址.
// Returns the URL segment value, eg: /page/:post_id
$postId = $this->param('post_id');
在某些情况下组件属性 可以充当硬编码值或引用 URL 中的值。
这个硬编码示例显示了带有标识符的博客文章2
正在使用:
url = "/blog/hard-coded-page"
[blogPost]
id = "2"
或者,可以使用一个从页面 URL 动态引用该值外部财产价值:
url = "/blog/:my_custom_parameter"
[blogPost]
id = "{{ :my_custom_parameter }}"
在这两种情况下,都可以使用property
方法:
$this->property('id');
如果需要访问路由参数名:
$this->paramName('id'); // Returns "my_custom_parameter"
处理页面执行周期
组件可以通过覆盖onRun
组件类中的方法。每次加载页面或布局时,CMS 控制器都会执行此方法。在方法内部,您可以通过page
财产:
public function onRun()
{
// This code will be executed when the page or layout is
// loaded and the component is attached to it.
$this->page['var'] = 'value'; // Inject some variable to the page
}
页面执行生命周期处理程序
当页面加载时,Winter 执行可以在布局和页面中定义的处理函数PHP 部分 和组件类。处理程序的执行顺序如下:
- 布局
onInit()
功能。 - 页
onInit()
功能。 - 布局
onStart()
功能。 - 布局组件
onRun()
方法。 - 布局
onBeforePageStart()
功能。 - 页
onStart()
功能。 - 页面组件
onRun()
方法。 - 页
onEnd()
功能。 - 布局
onEnd()
功能。
组件初始化
有时您可能希望在组件类首次实例化时执行代码。您可以覆盖init
组件类中的方法来处理任何初始化逻辑,这将在 AJAX 处理程序之前和页面执行生命周期之前执行。例如,此方法可用于将另一个组件动态附加到页面。
public function init()
{
$this->addComponent('Acme\Blog\Components\BlogPosts', 'blogPosts');
}
停止响应
像中的所有方法一样页面执行生命周期, 如果onRun
组件中的方法返回一个值,这将在此时停止循环并将响应返回给浏览器。在这里,我们使用Response
正面:
public function onRun()
{
if (true) {
return Response::make('Access denied!', 403);
}
}
您还可以从onRun
方法:
public function onRun()
{
if (true) {
$this->setStatusCode(404);
return $this->controller->run('404');
}
}
AJAX 处理程序
组件可以托管 AJAX 事件处理程序。它们在组件类中的定义与它们在页面或布局代码.在组件类中定义的示例 AJAX 处理程序方法:
public function onAddItem()
{
$value1 = post('value1');
$value2 = post('value2');
$this->page['result'] = $value1 + $value2;
}
如果这个组件的别名是demoTodo 可以通过访问此处理程序demoTodo::onAddItem
.请参阅调用组件中定义的 AJAX 处理程序 文章了解有关将 AJAX 与组件一起使用的详细信息。
默认标记
所有组件都可以带有默认标记,将其包含在页面上时使用{% component %}
标签,尽管这是可选的。默认标记保存在组件部分目录,与小写的组件类同名。
默认组件标记应放置在名为default.htm.例如,Demo ToDo 组件的默认标记在文件中定义/plugins/winter/demo/components/todo/default.htm.然后可以使用{% component %}
标签:
url = "/todo"
[demoTodo]
==
{% component 'demoTodo' %}
默认标记还可以采用覆盖组件属性 在它们被渲染的时候。
{% component 'demoTodo' maxItems="7" %}
这些属性将不可用onRun
方法,因为它们是在页周期完成后建立的。相反,它们可以通过覆盖onRender
组件类中的方法。 CMS 控制器在呈现默认标记之前执行此方法。
public function onRender()
{
// This code will be executed before the default component
// markup is rendered on the page or layout.
$this->page['var'] = 'Maximum items allowed: ' . $this->property('maxItems');
}
成分Partials
除了默认标记之外,组件还可以提供额外的部分,可以在前端或默认标记本身中使用。如果 Demo ToDo 组件有一个pagination 部分,它将位于/plugins/winter/demo/components/todo/pagination.htm 并显示在页面上使用:
{% partial 'demoTodo::pagination' %}
可以使用上下文相关的轻松方法。如果在组件部分内部调用,它将直接引用自身。如果在主题部分内部调用,它将扫描页面/布局上使用的所有组件以查找匹配的部分名称并使用它。
{% partial '@pagination' %}
多个组件可以通过将部分文件放在名为components/partials.当找不到通常的组件部分时,在此目录中找到的部分用作后备。例如,共享部分位于/plugins/acme/blog/components/partials/shared.htm 可以通过任何组件使用以下方式显示在页面上:
{% partial '@shared' %}
参考“自我”
组件可以通过使用__SELF__
多变的。默认情况下,它将返回组件的短名称或alias.
<form data-request="{{__SELF__}}::onEventHandler">
[...]
</form>
组件也可以引用它们自己的属性。
{% for item in __SELF__.items() %}
{{ item }}
{% endfor %}
如果在组件部分内部,您需要呈现另一个组件部分连接__SELF__
具有部分名称的变量:
{% partial __SELF__~"::screenshot-list" %}
唯一标识符
如果在同一页面上调用两次相同的组件,则id
属性可用于引用每个实例。
{{ __SELF__.id }}
每次显示组件时,ID 都是唯一的。
<!-- ID: demoTodo527c532e9161b -->
{% component 'demoTodo' %}
<!-- ID: demoTodo527c532ec4c33 -->
{% component 'demoTodo' %}
从代码渲染部分
您可以使用renderPartial
方法。这将检查部分命名的组件component-partial.htm
并将结果作为字符串返回。第二个参数用于传递视图变量。相同路径解析逻辑 当你像在 Twig 中一样在 PHP 中渲染一个组件时适用;使用@
前缀以引用组件本身内的部分。
$content = $this->renderPartial('@component-partial.htm');
$content = $this->renderPartial('@component-partial.htm', [
'name' => 'John Smith'
]);
例如,渲染部分作为对AJAX 处理程序:
function onGetTemplate()
{
return ['#someDiv' => $this->renderPartial('@component-partial.htm')];
}
另一个例子可能是通过从onRun
页循环法.此代码将使用Response
正面:
public function onRun()
{
$content = $this->renderPartial('@default.htm');
return Response::make($content)->header('Content-Type', 'text/xml');
}
使用组件注入页面资产
组件可以通过使用控制器的addCss
和addJs
将资产添加到 CMS 控制器的方法。这应该在组件的onRun
方法。见资产编译器 文档以获取更多信息
public function onRun()
{
$this->addJs('/plugins/acme/blog/assets/javascript/blog-controls.js');
}