我正在学习
javascript,顺便说一句,我正在努力学习更多有关jQuery的知识.我在JS中创建了一个非常简单的“表单控制器”,所以当我创建将表单作为参数传递的对象时,它会将事件连接起来并劫持提交:
var FormController = function (form) {
// private field
var _form = $(form);
var _url = _form.attr('action');
var _isValid = false;
$(form).submit(function (e) {
submitForm();
e.preventDefault();
});
var disableAll = function () {
_form.find('select,input,textarea').attr('disabled', 'disabled')
};
var enableAll = function () {
_form.find('select,input,textarea').removeAttr('disabled')
};
var submitForm = function () {
disableAll();
_isValid = true;
if (_isValid) {
$.ajax({
url: _url,
type: 'POST',
success: function (data, textStatus, jqXHR) {
enableAll();
var obj = jQuery.parseJSON(jqXHR.responseText);
print(data.Result ? data.Result : "[No Result]");
print(textStatus.toString());
},
error: function (data, textStatus, jqXHR) {
print(textStatus);
_form.css('border', '1px solid Red');
enableAll();
}
});
}
};
// public fields and functions
return {
getIsValid: function () { return _isValid; },
submit: function () { return submitForm(); }
};
};
它按预期工作.现在我想创建一个jQuery扩展,所以我可以将该对象应用于结果:
$.fn.formController = function () {
return this.each(function (i, item) {
new FormController(item);
});
};
我也按预期工作,但…… GC会收集那个对象吗?或者因为事件是有线的,它被视为参考?
现在,我想保持控制器的实例可用,因此我可以在创建后操作它们,例如用于调用方法.像这样的东西:
$('#myForm').formController('submit');
我已经尝试了几种方法来做到这一点,但我无法得到它.我试图用一个跟踪物品等的物品放置一个封闭物……但我只是弄乱了“这个”.
这样做的正确方法是什么?而且我认为到目前为止我所做的一切都可能是错的,即使它有效.
谢谢.
UPDATE
对不起,如果问题不够明确.我的目标是我能做的一种方式:$(‘#myForm’).formController(‘submit’);然后funcion将找到与该HTML对象关联的“FormController”对象,并调用此“submit”成员.
我希望实现这样的目标:
$.fn.formController = function (name) {
if(!document._items)
document._items = [];
if (name) {
return this.each(function (i, item) {
var id = $(item).data('form-controller');
if (id) {
var fc = document._items[id];
var member = fc[name];
if (member) {
if (typeof member == 'function')
member();
}
}
});
}
else {
return this.each(function (i, item) {
var id = document._items.push(new FormController(item)) - 1;
$(item).data('form-controller', id.toString());
});
}
};
这种方法的问题在于我将集合保持为全局对象,而我想要的是将其作为内部对象.我尝试过一个闭包,但我只遇到了“this”(指向DOMwindow)或“_items”var为空的问题.
接近这个的正确方法是什么?
最佳答案 您可以使用jQuery UI的Widget工厂,它为您提供开箱即用的功能:
$.widget("vtortola.formcontroller", {
_create: function() {
// Use `this.element` to initialize the element.
// You can also use this.options to get the options object that was passed.
},
_destroy: function() {
// You can unbind events here to remove references from the DOM, so is'll get
// deleted by the garbage collector.
},
submit: function() { /* ... */ }
});
// Example
$('#form').formcontroller({foo: 123}); // Calls `_create()` with the supplied options
$('#form').formcontroller('submit'); // Calls the `submit` method
小部件工厂还为您提供选项设置器/ getter,默认选项和其他很酷的东西.有关详细信息,请参见the official docs和tutorial at bililite.如果你没有将jQuery UI用于其他东西,你可以将widget factory code用作独立的,它不依赖于jQuery UI的其他部分.
如果你不喜欢使用jQuery UI的widget工厂,你可以直接将对象存储在.data()上(这也是widget工厂的工作),不需要保留它们的集合并手动跟踪它.您的代码将是以下内容:
$.fn.formController = function () {
var args = arguments;
return this.each(function (i, item) {
var $this = $(this), _obj;
// When calling `$(..)`.formController() with arguments when the object already
// exists, it treats the first argument as the method name and passes the rest
// as arguments to that method.
if (arguments.length && (_obj = $this.data('FormController'))) {
_obj[args[0]].apply(_obj, Array.prototype.slice.call(args, 1));
} else {
$this.data('FormController', new FormController(item));
}
});
};