我正在创建一个使用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。
答案 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)
内以涵盖所有基础。
还有可能阻止脚本在客户端被包含两次。这不是直接支持的,而且稍微麻烦一些,但在实践中它工作正常,并且它不需要您在服务器端知道客户端发生了什么(即已经包含哪些脚本)。
我们的想法是从服务器获取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