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

Yii renderpartial(proccessoutput=true)避免重复js请求,yii,renderpartial,clientscript,Yii,Renderpartial,Clientscript,我正在创建一个使用ajaxRequest的站点,当我单击一个链接时,它将使用ajaxRequest加载。当我加载例如user/login UserController actionLogin时,我将processOUtput的部分视图渲染为true,以便生成该视图中所需的js,但是如果我在该视图中使用事件注册clientScriptRegister,我如何避免根据ajaxRequest生成两次或多次scriptRegistered?我尝试了Yii::app()->clientScript->is

我正在创建一个使用ajaxRequest的站点,当我单击一个链接时,它将使用ajaxRequest加载。当我加载例如user/login UserController actionLogin时,我将processOUtput的部分视图渲染为true,以便生成该视图中所需的js,但是如果我在该视图中使用事件注册clientScriptRegister,我如何避免根据ajaxRequest生成两次或多次scriptRegistered?我尝试了
Yii::app()->clientScript->isSCriptRegistered('scriptId')
来检查脚本是否已注册,但如果使用ajaxRequest,则结果始终为false,因为只有在渲染完成后才会为true

控制器代码

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,则情况也是如此。。每次渲染Partial时都会调用corescript yiiactiveform。

以避免包含两次核心脚本 如果您的脚本已通过先前的请求包含,请使用此选项避免再次包含它们:

// 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;
如果您有独立呈现的视图以及作为HTML片段包含在AJAX中的视图,那么您可以将其包装在
If(Yii::app()->request->isAjaxRequest)
中,以覆盖所有基础

避免两次包含jQuery脚本(JS解决方案) 还可以防止脚本在客户端被包含两次。这是不直接支持的,而且有点麻烦,但在实践中,它工作得很好,并且不需要您知道服务器端在客户端发生了什么(即,已经包含了哪些脚本)

其思想是从服务器获取HTML,并用正则表达式replace简单地去掉
标记。重要的一点是,您可以检测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;
}
避免两次附加事件处理程序 您可以简单地使用Javascript对象来记住是否已经附加了处理程序;如果是,请不要再次连接。例如(视图代码):


要避免两次包含脚本文件,请尝试此扩展名:


要避免两次附加事件处理程序,请参见Jons的答案:

最干净的方法是重写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文件名,而不包括路径。

对于诸如yiiactiveform之类的核心脚本如何?jquery?顺便说一下,谢谢。这是
window.myCustomState=window.myCustomState | |{}在js中创建对象的简写?@butching:有关CoreScript,请参阅更新。对于对象创建语法,如果(!window.myCustomState)window.myCustomState={}
为避免两次包含核心脚本-->是,我使用该脚本删除核心脚本,但我的问题是,如果两个请求都是ajax,您如何知道该脚本已经包含在早期请求中?因为正如我前面所说的,在ajaxRequest中创建对象的结果总是错误的,是的,它很可爱,我明白了。。thx@butching:嗨,我用一个附加选项更新了答案。这会对已在主布局上初始化的已注册脚本产生影响吗?还是我必须在config main中注册脚本?实际上,您不应该在主布局中硬编码脚本(除非您确实需要).非常感谢您的反馈
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');
    })
  }
");
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);
  }

}