在 Yii 中从 registerScript 方法强制脚本顺序 [英] Forcing Script Order from registerScript Method in Yii

查看:18
本文介绍了在 Yii 中从 registerScript 方法强制脚本顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个小部件,它注册自己的脚本,如下所示

I created a widget that registers its own script like below

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

在布局中,我像这样调用小部件

And in the layout, I call the widget like this

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

但在视图文件中,我需要该小部件声明的变量.

But in a view file, I need the variable declared by that widget.

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

请注意,在两种 registerScript 方法中,我都使用 POS_END 作为脚本位置,因为我打算将所有脚本(包括 CoreScript,例如 jQuery、jQueryUI 等)放在 标签之后.

Note that in both registerScript method I use POS_END as the script position since I intend to put all of the scripts (including the CoreScript e.g. jQuery, jQueryUI etc) after the <body> tag.

问题在于渲染的脚本将显示视图文件中的一个,然后显示小部件中的一个.

The problem is that the rendered script will show the one from the view file and after that the one from the widget.

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

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

As we can see, the above code won't work so I need to put the the second line above the first line.

知道如何强制执行命令吗?我可以扩展 CClientScript(并创建一个新的 registerScript 方法),只要所有脚本都将在结束位置呈现并且我没有将上面的内嵌 Javascript 代码提取到新的包或文件中.

Any idea on how to force the order? I'm okay with extending the CClientScript (and creating a new registerScript method) as long as all of the scripts will be rendered in the end position and I don't have to pull those inline Javascript codes above to a new package or file.

推荐答案

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

So I finally find a hack to do this. I extend a new ClientScript class and modify the registerScript method so it will accept another param $level.

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

想想$level就像CSS中的z-index,除了$level的数量越多,位置越低脚本将是.

Think about $level just like z-index in CSS, except the greater the number of $level is, the lower the position of the script will be.

例如

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 的/code> 值大于 script3 的值.

Even though script3 is declared after script2, in the rendered script, it will show above script2 since the $level value of script2 is greater than script3's.

这是我的解决方案的代码.虽然我不确定排列方法是否足够优化,但它的工作方式符合我的要求.

Here's my solution's code. It's working like what I want although I'm not sure if the arranging method is optimized enough.

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

So I just need to put the class as the clientScript component in the config

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

这篇关于在 Yii 中从 registerScript 方法强制脚本顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆