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

Регистрация скриптов

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

  • registerJs() для встроенных скриптов
  • registerJsFile() для внешних скриптов

Регистрация встроенных скриптов

Встроенные скрипты полезны для настройки, динамически генерируемого кода и небольших фрагментов, созданных повторно используемым интерфейсом, содержащимся в виджетах. Метод registerJs () для их добавления может использоваться следующим образом:

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

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

  • View::POS_HEAD для заголовочной части.
  • View::POS_BEGIN после открытия <body>.
  • View::POS_END перед закрытием </body>.
  • View::POS_READY для выполнения кода в событии, подготовленном для документа. Это автоматически зарегистрирует jQuery и обернёт код в соответствующий код jQuery. Это позиция по умолчанию.
  • View::POS_LOAD для выполнения кода в событии загрузки документа. То же, что и выше, это также автоматически зарегистрирует jQuery.

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

Регистрация файлов сценариев

Аргументы registerJsFile() аналогичны аргументам для registerCssFile(). В следующем примере мы регистрируем файл main.js с зависимостью от yii\web\JqueryAsset. Это означает, что файл main.js будет добавлен ПОСЛЕ jquery.js. Без такой спецификации зависимостей относительный порядок между main.js и jquery.js был бы неопределен, и код не работал бы.

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

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

Это добавит тег для скрипта /js/main.js, расположенного под URL-адресом приложения.

Настоятельно рекомендуется использовать пучки активов для регистрации внешних JS-файлов, а не registerJsFile(), поскольку они обеспечивают лучшую гибкость и более подробную настройку зависимостей. Кроме того, использование пакетов ресурсов позволяет объединять и сжимать несколько файлов JS, что желательно для сайтов с высоким трафиком.

Регистрация CSS

Подобно JavaScript, вы можете зарегистрировать CSS, используя registerCss() или registerCssFile(). Первый регистрирует блок кода CSS, в то время как последний регистрирует внешний CSS-файл.

Регистрация встроенного CSS

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

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

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

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

Регистрация файлов CSS

Файл CSS можно зарегистрировать, используя следующее:

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

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

  • Первый аргумент указывает файл CSS, который необходимо зарегистрировать. @web в этом примере является псевдонимом для URL-адреса приложений.
  • Второй аргумент указывает атрибуты HTML для результирующего тега <link>. Этот параметр depends обрабатывается специально. Он определяет, от каких активов зависит этот CSS-файл. В этом случае зависимая группа ресурсов - это BootstrapAsset. Это означает, что файл CSS будет добавлен после файлов CSS из BootstrapAsset.
  • Последний аргумент указывает идентификатор, идентифицирующий этот файл CSS. Если он не указан, вместо него будет использоваться URL-адрес файла CSS.

Настоятельно рекомендуется использовать asset bundles для регистрации внешних CSS-файлов, а не registerCssFile(). Использование пакетов ресурсов позволяет объединять и сжимать несколько файлов CSS, что желательно для сайтов с высоким трафиком. Он также обеспечивает большую гибкость, поскольку все зависимости ресурсов вашего приложения настраиваются в одном месте.

Регистрация пакетов ресурсов

Как уже упоминалось ранее, рекомендуется использовать пакеты ресурсов вместо регистрации непосредственно файлов CSS и JavaScript. Что касается использования уже определенных пакетов ресурсов, это очень просто:

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

В приведенном выше коде в контексте файла представления пакет AppAsset зарегистрирован в текущем представлении (представленном $this). При регистрации пакетов ресурсов из виджета вместо этого вместо представления $widget будет использоваться $this->view.

Создание динамического Javascript

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

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

Регистрация глобальной конфигурации JavaScript

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

$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, например:

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

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

Передача переведенных сообщений

Вы можете столкнуться с ситуацией, когда ваш JavaScript должен распечатать сообщение, реагирующее на какое-либо событие. В приложении, которое работает с несколькими языками, эта строка должна быть переведена на текущий язык приложения. Одним из способов достижения этого является использование функции перевода сообщений, предоставляемой Yii, и передача результата в код JavaScript.

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

В приведенном выше примере кода используется синтаксис PHP Heredoc для лучшей читаемости. Это также позволяет лучше выделять синтаксис в большинстве IDE, поэтому это предпочтительный способ написания встроенного JavaScript, особенно полезный для кода, длина которого превышает одну строку. Переменная $message создается в PHP и благодаря Json::htmlEncode содержит строку в действительном синтаксисе JS, которая может быть вставлена в код JavaScript, чтобы поместить динамическую строку в вызов функции alert().