2012-07-25 19 views
6

Tôi tạo ra một widget mà đăng ký kịch bản riêng của mình như dưới đâyBuộc Script thứ tự từ registerScript Phương pháp trong Yii

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

Và trong cách bố trí, tôi gọi là phụ tùng như thế này

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

Nhưng trong một xem tập tin, tôi cần biến được khai báo bởi widget đó.

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

Lưu ý rằng trong cả hai phương pháp registerScript tôi sử dụng POS_END như vị trí kịch bản kể từ khi tôi có ý định đặt tất cả các kịch bản (bao gồm cả CoreScript ví dụ jQuery, jQueryUI vv) sau thẻ <body>.

Vấn đề là tập lệnh được hiển thị sẽ hiển thị tập lệnh từ tệp xem và sau đó là tệp từ tiện ích con.

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

Như chúng ta có thể thấy, mã trên sẽ không hoạt động nên tôi cần đặt dòng thứ hai phía trên dòng đầu tiên.

Bất kỳ ý tưởng nào về cách buộc thứ tự? Tôi đồng ý với việc mở rộng CClientScript (và tạo phương thức registerScript mới) miễn là tất cả các tập lệnh sẽ được hiển thị ở vị trí cuối và tôi không phải lấy các mã Javascript nội tuyến ở trên vào một gói hoặc tệp mới.

Trả lời

8

Vì vậy, cuối cùng tôi đã tìm thấy một hack để làm điều này. Tôi mở rộng một lớp ClientScript mới và sửa đổi phương thức registerScript để nó sẽ chấp nhận một thông số khác $level.

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

Hãy suy nghĩ về $level giống như z-index trong CSS, ngoại trừ lớn hơn số lượng $level là, càng thấp vị trí của kịch bản sẽ được.

Ví dụ

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); 

Mặc dù script3 được khai báo sau script2, trong kịch bản trả lại, nó sẽ hiển thị trên script2 vì giá trị $level của script2 lớn hơn script3 's.

Đây là mã của giải pháp của tôi. Nó làm việc như những gì tôi muốn mặc dù tôi không chắc chắn nếu phương pháp sắp xếp được tối ưu hóa đủ.

/** 
* 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; 
     } 
    } 
} 

Vì vậy, tôi chỉ cần đặt lớp như các thành phần clientscript trong cấu hình

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

Cố gắng đăng ký vào đầu

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

ý định của tôi là vẽ tất cả các kịch bản ở cuối dòng. Vấn đề là kịch bản trong widget phụ thuộc vào jQuery, và tôi đặt tất cả các coreScripts vào cuối bằng cách thiết lập trường 'coreScriptPosition' (http://www.yiiframework.com/doc/api/1.1/CClientScript#coreScriptPosition- chi tiết) dưới dạng POS_END. –

+0

Vâng, U có ý tưởng tồi hoặc U phải chia khai báo var thành HEAD, phần thân của tập lệnh widget ot END hoặc U phải thay đổi END thành READY: Yii :: app() -> clientScript-> registerScript ('script' , <<< JAVASCRIPT cảnh báo (a); JAVASCRIPT , CClientScript :: POS_READY); – Sergey

1

tôi đã đóng góp một bản vá để Yii cho phép đặt hàng (thêm vào trước, thêm, số lượng)

bạn có thể tìm thấy ở đây https://github.com/yiisoft/yii/pull/2263

nếu nó không được đặt vào vị trí của bạn, bạn có thể mở rộng CClientScript thành lớp của riêng bạn thành ap ply thay đổi của tôi

nhưng nói chung JS viết đúng cách sẽ hoạt động độc lập theo thứ tự ví dụ thay vì xác định một số phạm vi toàn cầu vars bạn có thể gán chúng làm thuộc tính cho cửa sổ (truy cập thuộc tính không tồn tại không ném lỗi trong js)

0

Không cần mở rộng CClienScript. Một giải pháp đơn giản cho vấn đề này là tạo một mảng $ script trong bộ điều khiển của bạn trong bộ điều khiển của bạn và thêm các kịch bản lệnh xem vào biến đó. Trong tệp bố trí của bạn Bạn sẽ đăng ký các tập lệnh được lưu trữ trong mảng $ scripts của bạn sau khi bạn đã đăng ký các tệp bạn muốn hiển thị trước đó. ví dụ .:

trong điều khiển của bạn

public $scripts = []; 

Trong bố cục của bạn:

$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); 

và theo quan điểm của bạn

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

Hiệu suất dễ nhất và hiệu quả nhất. –

+0

không, không hoạt động – surfer190

0

Ghi đè lên lớp CClientScript như @Petra đã nói, đây là mã tôi đang sử dụng, sau khi sử dụng mã @Petra và không làm việc cho tôi.

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; 
} 

} 

và sau đó, vào tập tin cấu hình của bạn, và trong các thành phần phần chỉnh sửa như sau:

'components' => array(
    . 
    . 
    'clientScript' => array(
     'class' => 'ClientScript' 
    ), 
) 
Các vấn đề liên quan