【问题标题】:jQuery extension and closuresjQuery 扩展和闭包
【发布时间】:2011-11-13 04:17:13
【问题描述】:

我正在学习 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');

我尝试了几种方法来做到这一点,但我无法做到。我试图用一个跟踪项目等的对象来封闭......但我只是把“这个”弄乱了。

这样做的正确方法是什么?而且我假设我到目前为止所做的一切都可能是错误的,即使它有效。

谢谢。

更新

对不起,如果问题不够清楚。我的目标是一种我可以做的方式:$('#myForm').formController('submit');,然后该函数将找到与该 HTML 对象关联的“FormController”对象,并调用此“提交”成员。

我想实现这样的目标:

$.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”变量为空的问题。

解决这个问题的正确方法是什么?

【问题讨论】:

    标签: javascript jquery closures


    【解决方案1】:

    您可以使用 jQuery UI 的小部件工厂,它为您提供了开箱即用的功能:

    $.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
    

    小部件工厂还为您提供选项 setter/getter、默认选项和其他很酷的东西。有关详细信息,请参阅 the official docstutorial at bililite。如果你不使用 jQuery UI 做其他东西,你可以单独使用widget factory code,它不依赖于 jQuery UI 的其他部分。

    如果您不喜欢使用 jQuery UI 的小部件工厂,您可以将对象直接存储在 .data() 上(这也是小部件工厂所做的),无需保留它们的集合并手动跟踪.您的代码将类似于:

    $.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));
            }
        });
    };
    

    【讨论】:

    • 谢谢。第二个例子不起作用,首先是因为“FromController”中有一个错字:D而且因为“arguments[0]”总是“0”,它不包含“提交”一词。知道为什么会这样吗?
    • 哦,arguments 指的是传递给each() 函数的参数。我更新了代码来解决这个问题。
    • 再次更新代码,缺少小部件名称的命名空间
    • 效果很好!太感谢了。这个例子将帮助我更好地理解 js 和 jQuery,并开始做我自己的扩展。再次感谢:)
    • 欢迎您,我很乐意提供帮助。我强烈建议您尝试将您的扩展程序编写为小部件,它为 OOP 代码提供了出色的基础架构,并为您提供了许多可以加快开发速度的常用实用程序。
    【解决方案2】:

    使用

    (function($){
        $.fn.formController = function(parameter1, parameter2){
                //this = #myForm
        }
    )(jQuery);
    

    并阅读this

    【讨论】:

    • 好吧,我感兴趣的是方法的内部,我自己到了那里:我想知道如何在该方法中创建一个带有数组的闭包,或者其他技术来实现我想要什么。
    • @vtortola:我没明白你,你想在里面做什么?
    • 好的,如你所见,当我调用“$('#theForm').formController()”时,我创建了一个对象“FormController”。我想要的是一种事后从该对象调用方法的方法。例如,“$('#theForm').formController('submit')”。为此,我需要在内部保留一个包含所有“FormController”实例的哈希表,但我不知道我可以使用什么有键,也不知道将集合放在哪里,或者如何去做。
    • @vtortola:我确实为您发布了代码,它正是您需要的! this 指的是#theForm
    • 是的,但是如何从表单对象中获取我之前创建的FormController实例呢?
    【解决方案3】:

    我也尝试过创建一个集合作为函数本身的属性。

    它有效,但我不知道它有多正确/合适:D

    $.fn.formController = function (name) {
    
        if (name) {
            return this.each(function (i, item) {
                var id = $(item).data('form-controller');
    
                if (id) {
                    var fc = $.fn.formController.Items[id];
                    print('get: ' + id + ' ' + (fc?'found':'not found'));
                    var member = fc[name];
                    if (member) {
                        if (typeof member == 'function')
                            member();
                    }
                }
            });
        }
        else {
    
            return this.each(function (i, item) {
                var id = $.fn.formController.Items.push(new FormController(item)) - 1;
                print('add: ' + id);
                $(item).data('form-controller', id.toString());
            });
        }
    };
    $.fn.formController.Items = [];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      • 2013-10-27
      • 2016-08-02
      • 2014-07-27
      相关资源
      最近更新 更多