组件开发

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 方法是必需的。该方法应返回一个包含两个键的数组:namedescription.名称和描述显示在 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,dropdownset.默认值: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 允许您从一系列选项中选择多个值。

的选项列表dropdownset 属性可以是静态的或动态的。静态选项定义为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'];
}

动态的dropdownset 列表可以依赖于其他属性。例如,州列表可能取决于所选国家/地区。依赖项声明为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 部分 和组件类。处理程序的执行顺序如下:

  1. 布局onInit() 功能。
  2. onInit() 功能。
  3. 布局onStart() 功能。
  4. 布局组件onRun() 方法。
  5. 布局onBeforePageStart() 功能。
  6. onStart() 功能。
  7. 页面组件onRun() 方法。
  8. onEnd() 功能。
  9. 布局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');
}

使用组件注入页面资产

组件可以通过使用控制器的addCssaddJs 将资产添加到 CMS 控制器的方法。这应该在组件的onRun 方法。见资产编译器 文档以获取更多信息

public function onRun()
{
    $this->addJs('/plugins/acme/blog/assets/javascript/blog-controls.js');
}
豫ICP备18041297号-2