5 关注者

小部件

小部件是在 视图 中使用的可重用构建块,用于以面向对象的方式创建复杂且可配置的用户界面元素。例如,日期选择器小部件可能会生成一个花哨的日期选择器,允许用户选择一个日期作为输入。您只需要在视图中插入以下代码即可

<?php
use yii\jui\DatePicker;
?>
<?= DatePicker::widget(['name' => 'date']) ?>

Yii 附带了大量小部件,例如 活动表单菜单jQuery UI 小部件Twitter Bootstrap 小部件。在下文中,我们将介绍关于小部件的基本知识。如果您想了解特定小部件的使用方法,请参考类 API 文档。

使用小部件

小部件主要用于 视图 中。您可以调用 yii\base\Widget::widget() 方法在视图中使用小部件。该方法接收一个用于初始化小部件的 配置 数组,并返回小部件的渲染结果。例如,以下代码插入了一个日期选择器小部件,该小部件被配置为使用俄语并保留输入在 $modelfrom_date 属性中。

<?php
use yii\jui\DatePicker;
?>
<?= DatePicker::widget([
    'model' => $model,
    'attribute' => 'from_date',
    'language' => 'ru',
    'dateFormat' => 'php:Y-m-d',
]) ?>

一些小部件可以接收一个内容块,该内容块应包含在调用 yii\base\Widget::begin()yii\base\Widget::end() 之间。例如,以下代码使用 yii\widgets\ActiveForm 小部件生成一个登录表单。该小部件将在分别调用 begin()end() 的地方生成 <form> 的开始和结束标签。两者之间的任何内容都将按原样呈现。

<?php
use yii\widgets\ActiveForm;
use yii\helpers\Html;
?>

<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>

    <?= $form->field($model, 'username') ?>

    <?= $form->field($model, 'password')->passwordInput() ?>

    <div class="form-group">
        <?= Html::submitButton('Login') ?>
    </div>

<?php ActiveForm::end(); ?>

请注意,与 yii\base\Widget::widget() 方法返回小部件的渲染结果不同,yii\base\Widget::begin() 方法返回小部件的实例,您可以使用该实例来构建小部件内容。

注意:一些小部件将使用 输出缓冲 来调整封闭内容,当 yii\base\Widget::end() 被调用时。因此,预计在同一个视图文件中调用 yii\base\Widget::begin()yii\base\Widget::end()。不遵循此规则可能会导致意外输出。

配置全局默认值

可以通过 DI 容器配置小部件类型的全局默认值

\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);

有关详细信息,请参阅 "依赖注入容器指南中的实际使用部分"

创建小部件

根据需求,小部件可以通过两种不同的方式创建。

1: 使用 `widget()` 方法

要创建小部件,请继承自 yii\base\Widget 并重写 yii\base\Widget::init() 和/或 yii\base\Widget::run() 方法。通常,`init()` 方法应该包含初始化小部件属性的代码,而 `run()` 方法应该包含生成小部件渲染结果的代码。渲染结果可以通过 `run()` 直接 "echo" 或者作为字符串返回。

在以下示例中,`HelloWidget` 对分配给其 `message` 属性的内容进行 HTML 编码并显示。如果未设置该属性,则默认显示 "Hello World"。

namespace app\components;

use yii\base\Widget;
use yii\helpers\Html;

class HelloWidget extends Widget
{
    public $message;

    public function init()
    {
        parent::init();
        if ($this->message === null) {
            $this->message = 'Hello World';
        }
    }

    public function run()
    {
        return Html::encode($this->message);
    }
}

要使用此小部件,只需在视图中插入以下代码:

<?php
use app\components\HelloWidget;
?>
<?= HelloWidget::widget(['message' => 'Good morning']) ?>

有时,小部件可能需要渲染大量内容。虽然可以在 `run()` 方法中嵌入内容,但更好的方法是将其放入 视图 中,并调用 yii\base\Widget::render() 来渲染它。例如:

public function run()
{
    return $this->render('hello');
}

2: 使用 `begin()` 和 `end()` 方法

这与上面类似,但略有不同。下面是 `HelloWidget` 的一个变体,它接收 `begin()` 和 `end()` 调用之间包含的内容,对其进行 HTML 编码,然后显示它。

namespace app\components;

use yii\base\Widget;
use yii\helpers\Html;

class HelloWidget extends Widget
{
    public function init()
    {
        parent::init();
        ob_start();
    }

    public function run()
    {
        $content = ob_get_clean();
        return Html::encode($content);
    }
}

如您所见,PHP 的输出缓冲区在 `init()` 中启动,以便 `init()` 和 `run()` 调用之间的任何输出都可以被捕获、处理并在 `run()` 中返回。

**信息:** 当您调用 yii\base\Widget::begin() 时,将创建一个小部件的新实例,并且 `init()` 方法将在小部件构造函数结束时被调用。当您调用 yii\base\Widget::end() 时,将调用 `run()` 方法,其返回值将被 `end()` 输出。

以下代码展示了如何使用这个 `HelloWidget` 的新变体:

<?php
use app\components\HelloWidget;
?>
<?php HelloWidget::begin(); ?>

    sample content that may contain one or more <strong>HTML</strong> <pre>tags</pre>

    If this content grows too big, use sub views

    For e.g.

    <?php echo $this->render('viewfile'); // Note: here render() method is of class \yii\base\View as this part of code is within view file and not in Widget class file ?>

<?php HelloWidget::end(); ?>

默认情况下,小部件的视图应存储在 `WidgetPath/views` 目录中的文件中,其中 `WidgetPath` 代表包含小部件类文件的目录。因此,上面的示例将渲染视图文件 `@app/components/views/hello.php`,假设小部件类位于 `@app/components` 下。您可以覆盖 yii\base\Widget::getViewPath() 方法来自定义包含小部件视图文件的目录。

最佳实践

小部件是重用视图代码的面向对象方式。

创建小部件时,您应该遵循 MVC 模式。一般来说,您应该将逻辑保留在小部件类中,并将演示保留在 视图 中。

小部件的设计应该自包含。也就是说,当使用小部件时,您应该能够将其直接放入视图中,而无需做任何其他事情。如果小部件需要外部资源(如 CSS、JavaScript、图像等),这可能会很棘手。幸运的是,Yii 提供了对 资产包 的支持,可以用来解决这个问题。

当小部件仅包含视图代码时,它与 视图 非常相似。实际上,在这种情况下,它们唯一的区别是,小部件是可重新分发的类,而视图只是一个普通的 PHP 脚本,您可能希望将其保留在应用程序中。

发现错字或您认为此页面需要改进?
在 GitHub 上编辑它 !