Формирование заказа скрипта из метода registerScript в Yii

Я создал виджет, который регистрирует свой собственный скрипт, как показано ниже.

class MyWidget extends CWidget { public function run(){ Yii::app()->clientScript->registerScript(__CLASS__, <<<JAVASCRIPT var a = "Hello World!"; JAVASCRIPT , CClientScript::POS_END); } } 

И в макете я вызываю виджет, как это

 <?php $this->widget('MyWidget');?> <?php echo $content;?> 

Но в файле вида мне нужна переменная, объявленная этим виджетами.

 <?php Yii::app()->clientScript->registerScript('script', <<<JAVASCRIPT alert(a); JAVASCRIPT , CClientScript::POS_END); ?> 

Обратите внимание, что в обоих методах registerScript я использую POS_END в качестве позиции сценария, так как после <body> я намерен поместить все сценарии (включая CoreScript, например jQuery, jQueryUI и т. Д.).

Проблема заключается в том, что визуализируемый скрипт покажет тот из файла вида, а затем тот из виджета.

 alert(a); var a = "Hello World!"; 

Как мы видим, приведенный выше код не будет работать, поэтому мне нужно поставить вторую строку над первой строкой.

Любая идея о том, как заставить заказ? Я в порядке с расширением CClientScript (и созданием нового метода registerScript ), пока все сценарии будут отображаться в конечной позиции, и мне не нужно вытаскивать эти встроенные коды Javascript выше в новый пакет или файл.

Related of "Формирование заказа скрипта из метода registerScript в Yii"

Поэтому я наконец нашел взломать это. Я расширяю новый класс ClientScript и ClientScript метод registerScript чтобы он принял другой параметр $level .

 public function registerScript($id, $script, $position = self::POS_END, $level = 1); 

Подумайте об $level как и в z-index в CSS, за исключением того, что чем больше число $level , тем ниже будет позиция скрипта.

Например

 Yii::app()->clientScript->registerScript('script1', '/** SCRIPT #1 **/', CClientScript::POS_END, 1); Yii::app()->clientScript->registerScript('script2', '/** SCRIPT #2 **/', CClientScript::POS_END, 2); Yii::app()->clientScript->registerScript('script3', '/** SCRIPT #3 **/', CClientScript::POS_END, 1); 

Несмотря на то, что script3 объявлен после script2 , в визуализированном скрипте он будет показан выше script2 поскольку значение $level для script2 больше, чем script3 .

Вот код моего решения. Он работает так, как я хочу, хотя я не уверен, что метод организации оптимизирован достаточно.

 /** * ClientScript manages Javascript and CSS. */ class ClientScript extends CClientScript { public $scriptLevels = array(); /** * Registers a piece of javascript code. * @param string $id ID that uniquely identifies this piece of JavaScript code * @param string $script the javascript code * @param integer $position the position of the JavaScript code. * @param integer $level the rendering priority of the JavaScript code in a position. * @return CClientScript the CClientScript object itself (to support method chaining, available since version 1.1.5). */ public function registerScript($id, $script, $position = self::POS_END, $level = 1) { $this->scriptLevels[$id] = $level; return parent::registerScript($id, $script, $position); } /** * Renders the registered scripts. * Overriding from CClientScript. * @param string $output the existing output that needs to be inserted with script tags */ public function render(&$output) { if (!$this->hasScripts) return; $this->renderCoreScripts(); if (!empty($this->scriptMap)) $this->remapScripts(); $this->unifyScripts(); //=================================== //Arranging the priority $this->rearrangeLevels(); //=================================== $this->renderHead($output); if ($this->enableJavaScript) { $this->renderBodyBegin($output); $this->renderBodyEnd($output); } } /** * Rearrange the script levels. */ public function rearrangeLevels() { $scriptLevels = $this->scriptLevels; foreach ($this->scripts as $position => &$scripts) { $newscripts = array(); $tempscript = array(); foreach ($scripts as $id => $script) { $level = isset($scriptLevels[$id]) ? $scriptLevels[$id] : 1; $tempscript[$level][$id] = $script; } foreach ($tempscript as $s) { foreach ($s as $id => $script) { $newscripts[$id] = $script; } } $scripts = $newscripts; } } } 

Поэтому мне просто нужно поместить класс в качестве компонента clientScript в конфигурацию

 'components' => array( 'clientScript' => array( 'class' => 'ClientScript' ) ) 

Попробуйте зарегистрироваться в HEAD

 Yii::app()->clientScript->registerScript(__CLASS__, <<<JAVASCRIPT var a = "Hello World!"; JAVASCRIPT , CClientScript::POS_HEAD); 

Я внедрил патч для Yii, чтобы разрешить упорядочивание (добавление, добавление, число)

вы можете найти его здесь https://github.com/yiisoft/yii/pull/2263

если он не попадает в вас, то вы можете расширить CClientScript на свой собственный класс, чтобы применить мои изменения

но в целом правильно написанная JS должна работать независимо от порядка, например, вместо того, чтобы определять некоторые глобальные области видимости, которые вы можете назначить им как свойства окна (доступ к несуществующему свойству не вызывает ошибку в js)

Нет необходимости расширять CClienScript. Простым решением этой проблемы было бы создание массива $ script в контроллере вашего контроллера и добавление сценариев представления к этой переменной. В вашем файле макета. Вы зарегистрировали бы скрипты, хранящиеся в массиве $ scripts, после того, как вы зарегистрировали те, которые хотите получить перед ним. например:

в вашем контроллере

 public $scripts = []; 

В вашем макете:

 $baseURL = Yii::app()->request->baseUrl; $clientScript = Yii::app()->clientScript; $clientScript->registerScriptFile( $baseURL . '/js/jquery.min.js', CClientScript::POS_END ); $clientScript->registerScriptFile( $baseURL . '/js/bootstrap.min.js', CClientScript::POS_END); 

и, на ваш взгляд

 <?php array_push($this->scripts,"/js/summernote.min.js");?> 

Переопределите класс CClientScript, как сказал @Petra, вот код, который я использую, после использования кода @Petra и не работал для меня.

 class ClientScript extends CClientScript { public $scriptLevels; public function registerScript($id, $script, $position = null, $level = 1, array $htmlOptions = array()) { $this->scriptLevels[$id] = $level; return parent::registerScript($id, $script, $position, $htmlOptions); } public function render(&$output) { foreach ($this->scripts as $key => $value) { $this->scripts[$key] = $this->reorderScripts($value); } parent::render($output); } public function reorderScripts($element) { $tempScripts = array(); $buffer = array(); foreach ($element as $key => $value) { if (isset($this->scriptLevels[$key])) { $tempScripts[$this->scriptLevels[$key]][$key] = $value; } } ksort($tempScripts); foreach ($tempScripts as $value) { foreach ($value as $k => $v) { $buffer[$k] = $v; } } return $buffer; } } 

а затем перейдите в свой конфигурационный файл, а в разделе компонентов измените следующее:

 'components' => array( . . 'clientScript' => array( 'class' => 'ClientScript' ), )