mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 18:47:33 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Виджеты
 | ||
| =======
 | ||
| 
 | ||
| Виджеты представляют собой многоразовые строительные блоки, используемые в [представлениях](structure-views.md)
 | ||
| для создания сложных и настраиваемых элементов пользовательского интерфейса в рамках объектно-ориентированного
 | ||
| подхода. Например, виджет выбора даты (date picker) позволяет генерировать интерактивный интерфейс для выбора дат,
 | ||
| предоставляя пользователям приложения удобный способ для ввода данных такого типа. Все, что нужно для
 | ||
| подключения виджета - это добавить следующий код в представление:
 | ||
| 
 | ||
| ```php
 | ||
| <?php
 | ||
| use yii\bootstrap\DatePicker;
 | ||
| ?>
 | ||
| <?= DatePicker::widget(['name' => 'date']) ?>
 | ||
| ```
 | ||
| 
 | ||
| В комплект Yii входит большое количество виджетов, например: [[yii\widgets\ActiveForm|active form]],
 | ||
| [[yii\widgets\Menu|menu]], [виджеты jQuery UI](https://github.com/yiisoft/yii2-jui/blob/master/docs/guide/README.md), [виджеты Twitter Bootstrap](https://github.com/yiisoft/yii2-bootstrap/blob/master/docs/guide/usage-widgets.md).
 | ||
| Далее будут представлены базовые сведения о виджетах. Для получения сведений относительно использования
 | ||
| конкретного виджета, следует обратиться к документации соответствующего класса.
 | ||
| 
 | ||
| 
 | ||
| ## Использование Виджетов <span id="using-widgets"></span>
 | ||
| 
 | ||
| Главным образом, виджеты применяют в [представлениях](structure-views.md). Для того, чтобы использовать виджет
 | ||
| в представлении, достаточно вызвать метод [[yii\base\Widget::widget()]]. Метод принимает массив [настроек](concept-configurations.md)
 | ||
| для инициализации виджета и возвращает результат его рендеринга. Например, следующий
 | ||
| код добавляет виджет для выбора даты, сконфигурированный для использования русского в качестве языка интерфейса
 | ||
| виджета и хранения вводимых данных в атрибуте `from_date` модели `$model`.
 | ||
| 
 | ||
| ```php
 | ||
| <?php
 | ||
| use yii\bootstrap\DatePicker;
 | ||
| ?>
 | ||
| <?= DatePicker::widget([
 | ||
|     'model' => $model,
 | ||
|     'attribute' => 'from_date',
 | ||
|     'language' => 'ru',
 | ||
|     'clientOptions' => [
 | ||
|         'dateFormat' => 'yy-mm-dd',
 | ||
|     ],
 | ||
| ]) ?>
 | ||
| ```
 | ||
| 
 | ||
| Некоторые виджеты могут иметь внутреннее содержимое, которое следует располагать между вызовами методов
 | ||
| [[yii\base\Widget::begin()]] и [[yii\base\Widget::end()]]. Например, для генерации формы входа, в следующем
 | ||
| фрагменте кода используется виджет [[yii\widgets\ActiveForm]]. Этот виджет сгенерирует открывающий и закрывающий
 | ||
| тэги `<form>` в местах вызова методов `begin()` и `end()` соответственно. При этом, содержимое, расположенное
 | ||
| между вызовами указанных методов будет выведено без каких-либо изменений.
 | ||
| 
 | ||
| ```php
 | ||
| <?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()]] возвращает экземпляр виджета, который может быть
 | ||
| использован в дальнейшем для формирования его внутреннего содержимого.
 | ||
| 
 | ||
| ### Задание глобальных умолчаний
 | ||
| 
 | ||
| Глобальные умолчания для определённого типа виджета могут быть заданы через DI контейнер:
 | ||
| 
 | ||
| ```php
 | ||
| \Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
 | ||
| ```
 | ||
| 
 | ||
| Подробнее это описано в [подразделе «Практическое использование» раздела «Контейнер внедрения зависимостей»](concept-di-container.md#practical-usage).
 | ||
| 
 | ||
| ## Создание Виджетов <span id="creating-widgets"></span>
 | ||
| 
 | ||
| Для того, чтобы создать виджет, следует унаследовать класс [[yii\base\Widget]] и переопределить методы
 | ||
| [[yii\base\Widget::init()]] и/или [[yii\base\Widget::run()]]. Как правило, метод `init()` должен содержать
 | ||
| код, выполняющий нормализацию свойств виджета, а метод `run()` - код, возвращающий результат рендеринга виджета.
 | ||
| Результат рендеринга может быть выведен непосредственно с помощью конструкции "echo" или же возвращен
 | ||
| в строке методом `run()`.
 | ||
| 
 | ||
| В следующем примере, виджет `HelloWidget` HTML-кодирует и отображает содержимое, присвоенное свойству `message`.
 | ||
| В случае, если указанное свойство не установлено, виджет, в качестве значения по умолчанию отобразит строку "Hello World".
 | ||
| 
 | ||
| ```php
 | ||
| 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
 | ||
| <?php
 | ||
| use app\components\HelloWidget;
 | ||
| ?>
 | ||
| <?= HelloWidget::widget(['message' => 'Good morning']) ?>
 | ||
| ```
 | ||
| 
 | ||
| Ниже представлен вариант виджета `HelloWidget`, который принимает содержимое, обрамленное вызовами методов
 | ||
| `begin()` и `end()`, HTML-кодирует его и выводит.
 | ||
| 
 | ||
| ```php
 | ||
| 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);
 | ||
|     }
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| Как Вы можете видеть, в методе `init()` происходит включение буферизации вывода PHP таким образом, что весь вывод
 | ||
| между вызовами `init()` и `run()` может быть перехвачен, обработан и возвращен в `run()`.
 | ||
| 
 | ||
| > Info: При вызове метода [[yii\base\Widget::begin()]] будет создан новый экземпляр виджета, при этом
 | ||
| вызов метода `init()` произойдет сразу после выполнения остального кода в конструкторе виджета.
 | ||
| При вызове метода [[yii\base\Widget::end()]], будет вызван метод `run()`, а возвращенное им значение будет выведено
 | ||
| методом `end()`.
 | ||
| 
 | ||
| Следующий фрагмент кода содержит пример использования модифицированного варианта `HelloWidget`:
 | ||
| 
 | ||
| ```php
 | ||
| <?php
 | ||
| use app\components\HelloWidget;
 | ||
| ?>
 | ||
| <?php HelloWidget::begin(); ?>
 | ||
| 
 | ||
|     content that may contain <tag>'s
 | ||
| 
 | ||
| <?php HelloWidget::end(); ?>
 | ||
| ```
 | ||
| 
 | ||
| В некоторых случаях, виджету может потребоваться вывести крупный блок содержимого. И хотя это содержимое может
 | ||
| быть встроено непосредственно в метод `run()`, целесообразней поместить его в [представление](structure-views.md)
 | ||
| и вызвать метод [[yii\base\Widget::render()]] для его рендеринга. Например,
 | ||
| 
 | ||
| ```php
 | ||
| public function run()
 | ||
| {
 | ||
|     return $this->render('hello');
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| По умолчанию, файлы представлений виджетов должны находиться в директории `WidgetPath/views`, где `WidgetPath` -
 | ||
| директория, содержащая файл класса виджета. Таким образом, в приведенном выше примере, для виджета будет
 | ||
| использован файл представления `@app/components/views/hello.php`, при этом файл с классом виджета расположен в
 | ||
| `@app/components`. Для того, чтобы изменить директорию, в которой содержатся файлы-представления для виджета,
 | ||
| следует переопределить метод [[yii\base\Widget::getViewPath()]].
 | ||
| 
 | ||
| 
 | ||
| ## Лучшие Практики <span id="best-practices"></span>
 | ||
| 
 | ||
| Виджеты представляют собой объектно-ориентированный подход к повторному использованию кода пользовательского
 | ||
| интерфейса.
 | ||
| 
 | ||
| При создании виджетов, следует придерживаться основных принципов концепции MVC. В общем случае, основную логику
 | ||
| следует располагать в классе виджета, разделяя при этом код, отвечающий за разметку в [представления](structure-views.md).
 | ||
| 
 | ||
| Разрабатываемые виджеты должны быть самодостаточными. Это означает, что для их использования должно быть
 | ||
| достаточно всего лишь добавить виджет в представление. Добиться этого бывает затруднительно в том случае,
 | ||
| когда для его функционирования требуются внешние ресурсы, такие как CSS, JavaScript, изображения и т.д.
 | ||
| К счастью, Yii предоставляет поддержку механизма для работы с ресурсами [asset bundles](structure-assets.md),
 | ||
| который может быть успешно использован для решения данной проблемы.
 | ||
| 
 | ||
| В случае, когда виджет не содержит логики, а содержит только код, отвечающий за вывод разметки, он мало
 | ||
| отличается от [представления](structure-views.md). В действительности, единственное его отличие состоит в том, что
 | ||
| виджет представляет собой отдельный и удобный для распространения класс, в то время как представление - это
 | ||
| обычный PHP скрипт, подходящий для использования только лишь в конкретном приложении.
 |