我正在尝试创建一个供自己使用的jQuery插件,可以使用单个命令为jQuery移动对话框设置处理程序:$('#dialog').setup_dialog({ callback: callback_function });
然而,我的处理程序由于其中的闭包而具有相当明显的内存泄漏:
$.fn.setup_dialog = function( options ) {
var settings = $.extend({
callback : 0
}, options);
var that = this;
return this.live('pagebeforeshow', function(event, ui) {
console.log("outside");
$('form', that).submit( function(e) {
var $inputs = $('form :input', that); // get all form inputs
var values = {};
$inputs.each(function() {
values[this.name] = $(this).val();
});
that.dialog('close');
if ( settings.callback && typeof(settings.callback) === "function" ) {
$('#'+ui.prevPage[0].id).live('pagebeforeshow', function() {
settings.callback(values, that);
console.log("inside");
});
}
return e.preventDefault();
});
});
}; /* setup_dialog */
如果您运行上面的代码,您会看到“内部”和“外部”首先打印一次,然后打印三次(一次提交两次),然后六次(单次提交三次),等等。 / p>
代码的目的是在jQuery Mobile对话框出现时附加一个事件处理程序,它将捕获表单提交,收集所有表单值,然后将它们传递给将修改原始页面的回调函数(启动了对话框)。
请注意,由于jQuery Mobile使用AJAX在页面之间切换的方式,我需要使用.live来绑定事件(.bind或.one将不起作用)。
我有什么想法可以避免事件积累(也可能会稍微清理一下代码)?
答案 0 :(得分:0)
您正在绑定其他事件处理程序内的事件处理程序。外部事件处理程序不是唯一的事件(它们不止一次出现),这意味着您的内部事件处理程序被绑定不止一次。
一个好的解决方法是从submit
事件处理程序中删除pagebeforeshow
事件处理程序,并将其放在pagecreate
或pageinit
事件处理程序中(这些是唯一的,并且会每个对话框只运行一次。)
如果你想保留当前的逻辑,那么你可以在它们运行时取消绑定事件处理程序,这样你就不会堆叠多个执行相同操作的事件处理程序:
$.fn.setup_dialog = function( options ) {
var settings = $.extend({
callback : 0
}, options);
var that = this;
return this.live('pagebeforeshow', function(event, ui) {
console.log("outside");
$('form', that).submit( function(e) {
var $inputs = $('form :input', that); // get all form inputs
var values = {};
$inputs.each(function() {
values[this.name] = $(this).val();
});
that.dialog('close');
if ( settings.callback && typeof(settings.callback) === "function" ) {
$('#'+ui.prevPage[0].id).live('pagebeforeshow', function() {
settings.callback(values, that);
console.log("inside");
$(this).die('pagebeforeshow');//NEW, unbind the pagebeforeshow event handler for this element
//since it will be bound the next time the dialog is shown anyway
});
}
$(this).die('submit');//NEW, unbind the submit event handler for this form
//since it will be bound the next time the dialog is shown anyway
return e.preventDefault();
});
});
}; /* setup_dialog */
以下是.die()
的文档:http://api.jquery.com/die/
答案 1 :(得分:0)
解决方案似乎如下:
$.fn.setup_dialog = function( options ) {
var settings = $.extend({
callback : 0
}, options);
var that = this; var values = {}; var submitted = 0;
this.on('pageinit', function(event, ui) {
$('form', that).submit(function(e) {
var $inputs = $('form :input', that); // get all form inputs
submitted = 1;
$inputs.each(function() {
values[this.name] = $(this).val();
});
that.dialog('close');
return e.preventDefault();
});
$('.cancel-button', that).click(function() {
submitted = 0;
});
});
this.on('pagebeforehide', function(event, ui) {
if ( submitted && settings.callback && typeof(settings.callback) === "function" ) {
settings.callback(values, that);
}
});
}; /* setup_dialog */
有多种方法可以做到这一点,包括创建一个闭包并调用$('#'+ui.prevPage[0].id).die().live('pagebeforeshow', function() {
不相信这是最好的解决方案,所以我很想听到一些更好的想法。