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

Современные веб-приложения, помимо статических 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'
);

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

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

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

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

Аргументы для 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()]]
);

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

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

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

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

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

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

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

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

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

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

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

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

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

Для регистрации внешних CSS файлов вместо registerCssFile() настоятельно рекомендуется использовать пакеты ресурсов. Это позволяет комбинировать и сжимать несколько CSS файлов, что желательно для сайтов с высоким трафиком. Также обеспечивается большая гибкость, поскольку все зависимости ресурсов вашего приложения настраиваются в одном месте.

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

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

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

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

В приведенном выше коде, в контексте файла представления, пакет AppAsset зарегистрирован в текущем представлении ($this). При регистрации пакетов ресурсов из виджета вы должны передать $view виджета, вместо ($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().

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

Скрипт yii.js

Примечание: Этот раздел еще не написан. Он должен содержать объяснение функциональности, предоставляемой yii.js:

  • JavaScript модули Yii
  • Обработчик параметра CSRF
  • Обработчик data-confirm
  • Обработчик data-method
  • Фильтрация скриптов
  • Обработка перенаправления