Подтвердить что ты не робот

Добавление Javascript для каждого представления в CakePHP

В попытке сохранить мои скрипты под контролем, я собираюсь перенести их в свой собственный файл, организованный контроллером и действием:

// scripts which only apply to /views/posts/add.ctp
/app/webroot/js/page/posts/add.js

// scripts which only apply to /view/users/index.ctp
/app/webroot/js/page/users/index.js

Все это круто, но я бы хотел, чтобы они автоматически добавлялись контроллером, поскольку он, очевидно, знает имя как контроллера, так и действия.

Я считаю, что лучшее место для этого в AppController::beforeRender(). (Да?)

Единственная проблема заключается в том, что я не знаю, как добавить это в переменную $scripts_for_layout. Я думал, что получение ссылки на вспомогательный объект javascript будет работать, но я не могу найти его с контроллера!

class AppController extends Controller {
    var $helpers = array("javascript", "html", "form");

    function beforeRender() {
        // ???
    }
}
4b9b3361

Ответ 1

Очень легко сделать в вашем макете default.ctp:

Пример автоматического включения файлов .css на контроллер и/или контроллер/действие (потому что у меня было это, легко адаптируемое к файлам .js):

<head>
...
<?php
    if (is_file(WWW_ROOT . 'css' . DS . $this->params['controller'] . '.css')) {
        echo $html->css($this->params['controller']);
    }
    if (is_file(WWW_ROOT . 'css' . DS . $this->params['controller'] . DS . $this->params['action'] . '.css')) {
        echo $html->css($this->params['controller'] . '/' . $this->params['action']);
    }
?>
...
</head>

Ответ 2

Как говорится в deceze, мы делаем это с использованием макета, хотя я считаю наше решение немного более элегантным:)

В default.ctp:

if(isset($cssIncludes)){
    foreach($cssIncludes as $css){
        echo $html->css($css);
    }
}

if(isset($jsIncludes)){
    foreach($jsIncludes as $js){
        echo $javascript->link($js);
    }
}

Затем в наших действиях контроллера мы определяем эти массивы:

$this->set('cssIncludes',array('special')); // this will link to /css/special.css
$this->set('jsIncludes',array('jquery'));   // this will link to /js/jquery.js

Для файлов, которые должны быть загружены в каждом представлении, мы просто добавляем один и тот же тип ссылки "статически" в начало макета, например:

echo $javascript->link('global');
echo $html->css('global');

Это действительно хорошо для нас. Удачи!

Ответ 3

К новинке к этому, но после прочтения это добавило следующее в мой макет:

if ($handle = opendir(WWW_ROOT . 'js' . DS . $this->params['controller'] . DS . $this->params['action'])) 
{
    while (false !== ($entry = readdir($handle)))
        {
           $entry = str_replace(".js", "", $entry);
           echo $this->Html->script($entry);

    }
    closedir($handle);
}

Ответ 4

Мне просто нужно было включить включение страницы, но я нашел более аккуратный способ сделать это в документации. Вы можете просто загрузить его в какой-то блок script в default.ctp. И в соответствующем представлении просто используйте HTML-помощник, чтобы нажать script:

Вы можете добавить тэг script к определенному блоку с помощью блока вариант:

echo $this->Html->script('wysiwyg', array('block' => 'scriptBottom'));

Что добавляет <script type="text/javascript" href="/js/wysiwyg.js"></script> к блоку.

В вашем макете вы можете вывести все теги script, добавленные в "ScriptBottom:

echo $this->fetch('scriptBottom');

Ответ 5

Лучший способ, который я могу придумать, - создать собственный пользовательский AppView и использовать все ваши контроллеры:

class myController extends AppController {
  var view = 'AppView';
  ...
}

Затем, где-то в вашем AppView, вы хотите сделать что-то вроде:

function __construct(&$controller, $register){
  parent::__construct($controller,$register);
  $this->addScript('<script type="text/javascript" src="/path/to/js/' . $this->controller . '/' . $this->action . '.js"></script>');
}

Но я бы сделал шаг назад и сначала подумал о нескольких вещах.

Насколько велики ваши сценарии, в среднем? Являются ли накладные расходы внешним script вызовом (до script кэшируется клиентом) лучше, чем добавление нескольких сотен байт в ваш основной поток вывода (просто вставив script на страницу, встроенный)?

Возможно, вам лучше где-нибудь посередине - разбить скрипты на контроллер, но не на действие. Таким образом, после первого посещения любого действия клиент имеет все сценарии для всех действий. Таким образом, вы избегаете большой начальной загрузки для всего приложения script, но вы избегаете добавления N-раундов-раундов (где N - количество действий, которые посещают новые пользователи).

Другой способ подойти к проблеме - сделать все это в javascript. Просто выясните схему ленивой загрузки. Таким образом, ваше приложение загружает очень маленький loader.js и что script определяет, какие другие источники javascript втянуть.

Примечание. Я никогда не тестировал свой взломанный вид, но я уверен, что это сработает, если вы действительно захотите это сделать.

Ответ 6

Там есть гайки и болты сообщения блога CakePHP на Соглашение о конфигурации - что такое большая сделка? - в которой используется помощник для указания файлов Javascript

<?php

class JsManagerHelper extends AppHelper {

    var $helpers = array('Javascript');

    //where our jQuery path relevant to CakePHP JS dir?
    var $_jqueryPath = 'jquery';

    //where do we keep our page/view relevant scripts?
    var $_pageScriptPath = 'page_specific';

    function myJs() {
    return $this->Javascript->link($this->_jqueryPath . '/' .
                                    $this->_pageScriptPath .'/' .
                                    $this->params['controller'] . '_' .
                                    $this->params['action'], false);
    }

}

?>

И тогда у вас просто $jsManager->myJs(); в вашем представлении.

Ответ 7

Я создал плагин для этой точной проблемы.

Если у вас есть два файла:

  • /app/View/Post/add.ctp
  • /app/View/Post/add.js

он будет включать add.js в блок script страницы.

ИЛИ

  • приложение /View/Post/add.js
  • приложение/Webroot/JS/пост/add.js

он будет включать /js/post/add.js в блок script страницы.

Несколько милых функций находятся там, и это просто, как beans. Вы даже можете использовать PHP внутри своих .js файлов и использовать viewVars, которые вы установили в действии. Больше всего вам не нужно взломать файлы вида или макета, чтобы заставить его работать, просто извлеките блок "script" в макете. Вы также можете просто записать .js в другой блок просмотра.

Вы можете проверить это здесь: https://github.com/dizyart/cakephp-viewautoload

Это на ранних стадиях, поэтому обязательно оставляйте комментарии и пожелания!

Ответ 8

LI работал немного (очень немного) над фрагментом W1ckd и упростил совместное использование одних и тех же js для разных действий:

if ( is_dir(WWW_ROOT . 'js' . DS . $this->params['controller'] ) && ( $handle = opendir( WWW_ROOT . 'js' . DS . $this->params['controller'] ) ) )
{
    while ( false !== ( $entry = readdir( $handle ) ) )
    {
        if ( in_array( $this->params['action'], explode( '.', $entry ) ) ) {
            $entry = str_replace( ".js", "", $entry );
            echo $this->Html->script( $this->params['controller'].DS.$entry );
        }

    }
    closedir( $handle );
}

Таким образом вы можете иметь что-то вроде:

Webroot/JS/ контроллер/view.edit.add.js

И этот js будет включен в эти три действия (просмотр, редактирование, добавление).

Ответ 9

С Cake v3 вы можете сделать это вот так. Добавьте скрипты в конкретный контроллер.

//YourController.php
public function beforeRender (Event $event)
{
    array_push($this->scripts, 'Admin/gallery');
    parent::beforeRender($event);
}

Задайте значение по умолчанию для инициализации и рендеринга.   //AppController.php   публичная функция initialize()   {       Родитель:: инициализации();

    $this->scripts = [];
}

public function beforeRender (Event $event)
{
    /* Define scripts in beforeRender of Child */
    $this->set('scripts', $this->scripts);
    /*-----------------------------------------*/
}

Теперь вы можете запустить эту функцию один раз.

<?= $this->Html->script($scripts) ?>