Работа с клиентскими скриптами
===========================

Современные веб-приложения, помимо статических HTML-страниц, содержат JavaScript, который используется для изменения страницы в браузере путем манипулирования существующими элементами или загрузки нового контента используя AJAX.

В этом разделе описываются методы, предоставляемые Yii для добавления JavaScript и CSS на веб-сайт, а также их динамическая настройка.

## Регистрация скриптов <span id="register-scripts"></span>

При работе с объектом [[yii\web\View]] можно динамически регистрировать интерфейсные скрипты.
Для этого есть два специальных метода:

- [[yii\web\View::registerJs()|registerJs()]] для встраиваемых, в тело страницы, скриптов
- [[yii\web\View::registerJsFile()|registerJsFile()]] для подключаемых, из внешних файлов, скриптов

### Регистрация встраиваемых скриптов <span id="inline-scripts"></span>

Встраиваемые скрипты полезны для конфигурации динамически генерируемого кода и небольших повторно используемых фрагментов интерфейса, содержащимся в [виджетах](structure-widgets.md).
Для их добавления можно использовать метод [[yii\web\View::registerJs()|registerJs()]] следующим образом:

```php
$this->registerJs(
    "$('#myButton').on('click', function() { alert('Button clicked!'); });",
    View::POS_READY,
    'my-button-handler'
);
```

Первый аргумент - это JavaScript-код, который мы хотим вставить на страницу. Он будет обёрнут в тег `<script>`. Второй аргумент определяет, в какой позиции скрипт должен быть вставлен на страницу.
Возможные значения:

- [[yii\web\View::POS_HEAD|View::POS_HEAD]] в `<head>`
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] сразу после открытия тега `<body>`
- [[yii\web\View::POS_END|View::POS_END]] сразу после закрытия тега `</body>`
- [[yii\web\View::POS_READY|View::POS_READY]] для выполнения кода сразу после того, как DOM полностью загрузился. Этому соответствует [событие `ready`](https://learn.jquery.com/using-jquery-core/document-ready/). При этом автоматически зарегистрируется [[yii\web\JqueryAsset|jQuery]]. Код будет обёрнут в соответствующий код jQuery. `POS_READY` является позицией по умолчанию.
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] для выполнения кода после того, как DOM полностью загрузился (включая картинки). [Событие `load`](https://learn.jquery.com/using-jquery-core/document-ready/). Так же, как и выше, при этом автоматически зарегистрируется [[yii\web\JqueryAsset|jQuery]]

Последний аргумент — это уникальный ID, который используется для идентификации блока со скриптом. При повторной регистрации происходит замена существующего скрипта на новый. Если вы не зададите ID, вместо него будет использоваться сам код. Это помогает избежать регистрации одного и того же кода несколько раз.

### Регистрация внешнего файла скриптов <span id="script-files"></span>

Аргументы для [[yii\web\View::registerJsFile()|registerJsFile()]] аналогичны аргументам для [[yii\web\View::registerCssFile()|registerCssFile()]]. В следующем примере мы регистрируем `main.js` с зависимостью от [[yii\web\JqueryAsset]]. Это означает, что `main.js` будет добавлен после `jquery.js`. Без подобного указания зависимостей относительный порядок между `main.js` и `jquery.js` будет неопределенным, и код не будет работать.

Внешний скрипт может быть добавлен следующим образом:

```php
$this->registerJsFile(
    '@web/js/main.js',
    ['depends' => [\yii\web\JqueryAsset::class]]
);
```

Вместо [[yii\web\View::registerJsFile()|registerJsFile()]] для регистрации внешних JS-файлов настоятельно рекомендуется использовать [пакеты ресурсов](structure-assets.md), поскольку они обеспечивают лучшую гибкость и более детальную конфигурацию зависимостей. Использование пакетов ресурсов также позволяет объединять и сжимать несколько JS файлов, что желательно для веб-сайтов с высоким трафиком.

## Регистрация CSS <span id="register-css"></span>

Подобно JavaScript, вы можете зарегистрировать CSS используя [[yii\web\View::registerCss()|registerCss()]] или [[yii\web\View::registerCssFile()|registerCssFile()]].
Первый регистрирует блок кода CSS, а второй регистрирует внешний файл CSS.

### Регистрация встроенного CSS <span id="inline-css"></span>

```php
$this->registerCss("body { background: #f00; }");
```

Приведенный выше код добавит следующий код в секцию `<head>` страницы:

```html
<style>
body { background: #f00; }
</style>
```

Если вы хотите задать дополнительные свойства тега style, передайте массив вида «имя => значение» как второй аргумент.
Последний аргумент — это уникальный ID, который используется для идентификации блока стиля и обеспечения его добавления только один раз в случае, если один и тот же стиль зарегистрирован в разных местах кода.

### Регистрация CSS файлов <span id="css-files"></span>

Зарегистрировать CSS файл можно следующим способом:

```php
$this->registerCssFile("@web/css/themes/black-and-white.css", [
    'depends' => [\yii\bootstrap\BootstrapAsset::class],
    'media' => 'print',
], 'css-print-theme');
```

Приведенный выше код добавит ссылку на CSS файл `/css/themes/black-and-white.css` в секцию `<head>` страницы.

* Первый аргумент указывает CSS-файл для регистрации. `@web` в этом примере является [псевдонимом для базового URL-адреса приложения](concept-aliases.md#predefined-aliases).
* Второй аргумент указывает атрибуты HTML для результирующего тега `<link>`. Опция `depends` обрабатывается специально. Она указывает, от каких пакетов ресурсов зависит этот CSS файл. В этом случае зависимым пакетом ресурсов является [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. Это означает, что CSS файл будет добавлен *после* CSS файлов из [[yii\bootstrap\BootstrapAsset|BootstrapAsset]].
* Последний аргумент указывает ID, идентифицирующий этот CSS файл. Если он не указан, вместо него будет использоваться URL-адрес CSS файла.

Для регистрации внешних CSS файлов вместо [[yii\web\View::registerCssFile()|registerCssFile()]] настоятельно рекомендуется использовать [пакеты ресурсов](structure-assets.md). Это позволяет комбинировать и сжимать несколько CSS файлов, что желательно для сайтов с высоким трафиком. Также обеспечивается большая гибкость, поскольку все зависимости ресурсов вашего приложения настраиваются в одном месте.

## Регистрация пакетов ресурсов <span id="asset-bundles"></span>

Как упоминалось ранее, рекомендуется использовать пакеты ресурсов вместо регистрации CSS файлов и JavaScript напрямую.
Вы можете получить подробную информацию о том, как определить пакеты ресурсов в разделе ["Ресурсы"](structure-assets.md).

Готовый пакет ресурсов можно использовать так:

```php
\frontend\assets\AppAsset::register($this);
```

В приведенном выше коде, в контексте файла представления, пакет `AppAsset` зарегистрирован в текущем представлении (`$this`).
При регистрации пакетов ресурсов из виджета вы должны передать [[yii\base\Widget::$view|$view]] виджета, вместо (`$this->view`).

## Генерация динамического Javascript <span id="dynamic-js"></span>

Часто в файлах шаблонов представлений, HTML-код не записывается напрямую, а генерируется неким PHP-кодом, зависящим от переменных представления.
Для того, чтобы сгенерированный HTML мог работать с Javascript, код JS также должен содержать динамические части, например идентификаторы селекторов jQuery.

Чтобы вставить переменные PHP в код JS, их значения должны быть корректно экранированы. Особенно, когда код JS вставляется в HTML, а не находится в выделенном файле JS.
Для этой цели Yii предоставляет метод [[yii\helpers\Json::htmlEncode()|htmlEncode()]] хелпера [[yii\helpers\Json|Json]]. Его использование будет показано в следующих примерах.

### Регистрация глобальной конфигурации JavaScript <span id="js-configuration"></span>

В этом примере мы используем массив для передачи глобальных параметров конфигурации из PHP-части приложения в код интерфейса JS.

```php
$options = [
    'appName' => Yii::$app->name,
    'baseUrl' => Yii::$app->request->baseUrl,
    'language' => Yii::$app->language,
    // ...
];
$this->registerJs(
    "var yiiOptions = ".\yii\helpers\Json::htmlEncode($options).";",
    View::POS_HEAD,
    'yiiOptions'
);
```

Приведенный выше код зарегистрирует тег `<script>`, содержащий определение переменной JavaScript, например:

```javascript
var yiiOptions = {"appName":"My Yii Application","baseUrl":"/basic/web","language":"en"};
```

Теперь в вашем JavaScript коде вы можете получить к ним доступ, например: `yiiOptions.baseUrl` или `yiiOptions.language`.

### Передача сообщений перевода <span id="translated-messages"></span>

Вы можете столкнуться со случаем, когда ваш JavaScript должен вывести сообщение, реагирующее на какое-то событие. В приложении, которое работает с несколькими языками, эта строка должна быть переведена на текущий язык приложения.
Один из способов достичь этого — использовать [интернационализацию](tutorial-i18n.md#message-translation), предоставляемую Yii и передавать результат в код JavaScript.

```php
$message = \yii\helpers\Json::htmlEncode(
    \Yii::t('app', 'Button clicked!')
);
$this->registerJs(<<<JS
    $('#myButton').on('click', function() { alert( $message ); });
JS
);
```

Приведенный выше пример кода использует PHP [синтаксис Heredoc](https://www.php.net/manual/ru/language.types.string.php#language.types.string.syntax.heredoc) для лучшей читаемости. Это также обеспечивает лучшую подсветку синтаксиса в большинстве IDE, поэтому это предпочтительный способ написания встроенного JavaScript, особенно полезный для кода, более длинного чем однострочный. Переменная `$message` создается PHP и благодаря [[yii\helpers\Json::htmlEncode|Json::htmlEncode]] содержит строку в допустимом синтаксисе JS, которую можно вставить в JavaScript код, чтобы поместить динамическую строку в вызов функции `alert()`.

> Note: При использовании Heredoc, будьте осторожны с именами переменных в коде JS, поскольку переменные, начинающиеся с `$`, могут интерпретироваться как переменные PHP, которые будут заменены их содержимым.
> jQuery функция в форме `$(` или `$.` не интерпретируется как переменная PHP и может безопасно использоваться.

## Скрипт `yii.js`<span id="yii.js"></span>

> Note: Этот раздел еще не написан. Он должен содержать объяснение функциональности, предоставляемой `yii.js`:
> 
> - JavaScript модули Yii
> - Обработчик параметра CSRF
> - Обработчик `data-confirm`
> - Обработчик `data-method`
> - Фильтрация скриптов
> - Обработка перенаправления
