Yii中

2012-07-25 64 views
6

從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!"; 

正如我們所看到的,上面的代碼不會工作,所以我需要把第二行放在第一行上面。

關於如何強制訂單的任何想法?只要所有腳本都將呈現在最終位置,並且我不必將上面的內聯Javascript代碼拖到新的包或文件中,我就可以擴展CClientScript(並創建新的registerScript方法)。

回答

8

所以,我終於找到一個黑客做到這一點。我擴展了一個新的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); 

即使script3script2後宣佈,在渲染的腳本,它會顯示上述script2script2$level值大於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' 
) 
) 
1

嘗試註冊HEAD

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

我的目的是使所有的端腳本。事情是小部件中的腳本依賴於jQuery,並且我通過設置'coreScriptPosition'字段來完成所有的coreScripts(http://www.yiiframework.com/doc/api/1.1/CClientScript#coreScriptPosition-細節)作爲POS_END。 – 2012-07-26 08:28:04

+0

那麼,你有不好的主意,或者U必須將var聲明分割爲HEAD,小部件主體腳本END或U必須將END更改爲READY:Yii :: app() - > clientScript-> registerScript('script' ,警報(a); JAVASCRIPT ,CClientScript :: POS_READY); – Sergey 2012-07-26 09:33:27

1

我已經貢獻了一個補丁的Yii允許排序(前置,追加,數量)

,你可以在這裏找到 https://github.com/yiisoft/yii/pull/2263

,如果它沒有得到它的地方變成你,那麼你可以擴展CClientScript到自己的類以AP簾布我的變化

但總體正確寫入JS例如應當定義一些全局範圍內乏,你可以將它們分配爲屬性窗口(訪問不存在財產的順序 獨立工作,而不是不扔在JS錯誤)

0

不需要擴展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");?> 
+0

最簡單和最好的性能。 – 2015-12-30 06:19:15

+0

不行,不起作用 – surfer190 2016-09-02 18:44:28

0

覆蓋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' 
    ), 
)