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 方法中,我都使用 POS_END 作为脚本位置,因为我打算将所有脚本(包括 CoreScript,例如 jQuery、jQueryUI 等)放在<body>标记之后。

问题是渲染的脚本将显示来自视图文件的脚本,然后显示来自小部件的脚本。

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

正如我们所看到的,上面的代码不起作用,所以我需要将第二行放在第一行之上。

关于如何强制订单的任何想法?我可以扩展CClientScript(并创建一个新registerScript方法),只要所有脚本都将呈现在结束位置,并且我不必将上面的那些内联 Javascript 代码拉到新的包或文件中。

4

5 回答 5

9

所以我终于找到了一个黑客来做到这一点。我扩展了一个新ClientScript类并修改了registerScript方法,以便它接受另一个参数$level

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

就像在 CSS 中$level一样z-index,除了 is 的数量越大,$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因为 的$levelscript2大于script3's。

这是我的解决方案的代码。它就像我想要的那样工作,虽然我不确定排列方法是否足够优化。

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

我已经为 Yii 提供了一个补丁来允许排序(前置、附加、编号)

你可以在这里找到它 https://github.com/yiisoft/yii/pull/2263

如果它没有进入您的位置,那么您可以将 CClientScript 扩展到您自己的类以应用我的更改

但通常正确编写的 JS 应该独立于顺序工作,例如,而不是定义一些全局范围变量,您可以将它们作为属性分配给窗口(访问不存在的属性不会在 js 中引发错误)

于 2013-03-26T14:54:45.113 回答
1

尝试注册到 HEAD

Yii::app()->clientScript->registerScript(__CLASS__, <<<JAVASCRIPT
var a = "Hello World!";
JAVASCRIPT
, CClientScript::POS_HEAD);
于 2012-07-26T05:30:38.590 回答
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 回答