7

以下のように独自のスクリプトを登録するウィジェットを作成しました

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メソッドでも、すべてのスクリプト(jQuery、jQueryUIなどのCoreScriptを含む)を<body>タグの後に配置するため、スクリプトの位置としてPOS_ENDを使用していることに注意してください。

問題は、レンダリングされたスクリプトがビューファイルからのものを表示し、その後ウィジェットからのものを表示することです。

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

ご覧のとおり、上記のコードは機能しないため、2行目を1行目より上に配置する必要があります。

注文を強制する方法について何かアイデアはありますか?すべてのスクリプトが終了位置にレンダリングされ、上記のインラインJavascriptコードを新しいパッケージまたはファイルにプルする必要がない限り、拡張CClientScript(および新しいメソッドの作成)は問題ありません。registerScript

4

5 に答える 5

9

だから私はついにこれを行うためのハックを見つけました。ClientScript新しいクラスを拡張し、registerScript別のparamを受け入れるようにメソッドを変更し$levelます。

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

CSSの場合と$level同じように考えてください。ただし、の数が多いほど、スクリプトの位置は低くなります。z-index$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、レンダリングされたスクリプトでは、の値が'sより大きいscript2ため、上に表示されます。$levelscript2script3

これが私のソリューションのコードです。アレンジ方法が十分に最適化されているかどうかはわかりませんが、私が望むように機能しています。

/**
 * 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'
  )
)
于 2012-07-27T02:10:21.273 に答える
1

HEADに登録してみてください

Yii::app()->clientScript->registerScript(__CLASS__, <<<JAVASCRIPT
var a = "Hello World!";
JAVASCRIPT
, CClientScript::POS_HEAD);
于 2012-07-26T05:30:38.590 に答える
1

注文(追加、追加、番号)を可能にするパッチをYiiに提供しました

ここで見つけることができます https://github.com/yiisoft/yii/pull/2263

それがあなたにその場所を与えなかった場合、あなたは私の変更を適用するためにあなた自身のクラスにCClientScriptを拡張することができます

ただし、一般に、適切に記述されたJSは、順序に関係なく機能する必要があります。たとえば、グローバルスコープ変数を定義する代わりに、それらをウィンドウのプロパティとして割り当てることができます(存在しないプロパティにアクセスしてもjsでエラーは発生しません)

于 2013-03-26T14:54:45.113 に答える
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");?>
于 2014-10-19T15:13:10.933 に答える
0

@Petraが言ったように、CClientScriptクラスをオーバーライドします。これは、@ 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'
    ),
)
于 2014-11-06T08:21:01.277 に答える