Yii renderpartial(proccessoutput = true)避免重复的js请求

时间:2012-04-17 09:14:27

标签: yii renderpartial clientscript

我正在创建一个使用ajaxRequest的网站,当我点击链接时,它将使用ajaxRequest加载。当我加载例如user / login UserController actionLogin 时,我 renderPartial视图使用processOUtput为true 因此将生成该视图中所需的js,但是如果我在其中有clientScriptRegister那个带有事件的视图,我怎样才能避免根据ajaxRequest生成两次或多次scriptRegistered?我已经尝试Yii::app()->clientScript->isSCriptRegistered('scriptId')来检查脚本是否已经注册,但似乎如果你使用了ajaxRequest,结果总是为假,因为只有在渲染完成后它才会成立。

控制器代码

if (Yii::app()->request->isAjaxRequest)
{
   $this->renderPartial('view',array('model'=>$model),false,true);
}

查看代码

if (!Yii::app()->clientScript->isScriptregistered("view-script"))
   Yii::app()->clientScript->registerScript("view-script","
      $('.link').live('click',function(){
         alert('test');
     })
");

如果我是第一次请求控制器,它可以完美地工作(警报1次),但是如果我再次请求同一个控制器而不刷新我的页面而只是使用ajaxRequest,则单击它时警报将输出两次(因为它一直在生成,尽管你已经注册了一次)

如果你在jquery功能的视图中有 CActiveForm ,这是一样的。每次你在renderPartial时都会调用corescript yiiactiveform。

3 个答案:

答案 0 :(得分:24)

避免两次包含核心脚本

如果您的脚本已经包含在先前的请求中,请使用此脚本以避免再次包含它们:

// For jQuery core, Yii switches between the human-readable and minified
// versions based on DEBUG status; so make sure to catch both of them
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;

如果您有独立呈现的视图以及要包含在AJAX中的HTML片段,您可以将其包含在if (Yii::app()->request->isAjaxRequest)内以涵盖所有基础。

避免两次包含jQuery脚本(JS解决方案)

还有可能阻止脚本在客户端被包含两次。这不是直接支持的,而且稍微麻烦一些,但在实践中它工作正常,并且它不需要您在服务器端知道客户端发生了什么(即已经包含哪些脚本)。

我们的想法是从服务器获取HTML并简单地删除带有正则表达式替换的<script>标记。重要的是你可以检测jQuery核心脚本和插件是否已经加载(因为它们创建了$或属性)并且有条件地执行此操作:

function stripExistingScripts(html) {
    var map = {
        "jquery.js": "$",
        "jquery.min.js": "$",
        "jquery-ui.min.js": "$.ui",
        "jquery.yiiactiveform.js": "$.fn.yiiactiveform",
        "jquery.yiigridview.js": "$.fn.yiiGridView",
        "jquery.ba-bbq.js": "$.bbq"
    };

    for (var scriptName in map) {
        var target = map[scriptName];
        if (isDefined(target)) {
            var regexp = new RegExp('<script.*src=".*' +
                                    scriptName.replace('.', '\\.') +
                                    '".*</script>', 'i');
            html = html.replace(regexp, '');
        }
    }

    return html;
}

如果已经包含相应的脚本,则会定义文件名和对象的映射;通过此函数传递传入的HTML,它将检查并删除与先前加载的脚本对应的<script>标记。

辅助函数isDefined就是这样:

function isDefined(path) {
    var target = window;
    var parts = path.split('.');

    while(parts.length) {
        var branch = parts.shift();
        if (typeof target[branch] === 'undefined') {
            return false;
        }

        target = target[branch];
    }

    return true;
}

避免连接事件处理程序两次

您可以简单地使用Javascript对象来记住您是否已经附加了处理程序;如果是,请不要再次附上。例如(查看代码):

Yii::app()->clientScript->registerScript("view-script","
  window.myCustomState = window.myCustomState || {}; // initialize if not exists
  if (!window.myCustomState.liveClickHandlerAttached) {
    window.myCustomState.liveClickHandlerAttached = true;
    $('.link').live('click',function(){
       alert('test');
    })
  }
");

答案 1 :(得分:6)

最干净的方法是覆盖beforeAction(),以避免任何重复的核心脚本:

class Controller extends CController {

  protected function beforeAction($action) {
        if( Yii::app()->request->isAjaxRequest ) {
            Yii::app()->clientScript->scriptMap['jquery.js'] = false;
            Yii::app()->clientScript->scriptMap['jquery-2.0.0.js'] = false;
            Yii::app()->clientScript->scriptMap['anything.js'] = false;
        }

        return parent::beforeAction($action);
  }

}

请注意,您必须输入精确的js文件名,而不是路径。

答案 2 :(得分:4)

要避免两次包含脚本文件,请尝试使用此扩展程序:http://www.yiiframework.com/extension/nlsclientscript/

要避免两次附加事件处理程序,请参阅Jons answer:https://stackoverflow.com/a/10188538/729324