1

今天早些时候我在玩小提琴,试图回答一个问题,发现了一个令人困惑的事情。作为一个 JS 新手,我无法自己调试出了什么问题。我什至尝试检查$.fn.showjQuery 源代码中的 source0 ,但无法弄清楚出了什么问题。

HTML:

<input type='text' id='dataBox'/>
<input type='button' value='toggle' id='toggleButton' />​

jQuery代码:

jQuery(function ($) {
    var _oldShow = $.fn.show;
    $.fn.show = function (speed, oldCallback) {
        return $(this).each(function () {
            var obj = $(this),
                newCallback = function () {

                    if ($.isFunction(oldCallback)) {
                        oldCallback.apply(obj);
                    }
                    obj.trigger('afterShow');
                };
            obj.trigger('beforeShow');
            if(speed)    
                _oldShow.apply(obj, [speed,newCallback]);
            else    
                _oldShow.apply(obj, [newCallback]);
        });
    }
});


$('#dataBox').bind('beforeShow', function () {
        alert('beforeShow');
    });


$('#toggleButton').click(function(){
        $('#dataBox').show();
}); 

问题是我犯了一些错误,导致这条线无限次执行 obj.trigger('beforeShow');

因此alert在这个块中

 $('#dataBox').bind('beforeShow', function () {
    alert('beforeShow');
 });  

似乎停不下来。

不管我要做什么,或者是否可以通过其他任何方式完成,有人可以在这里解释我做错了什么。我已经尝试了几个小时,但无法弄清楚。

小提琴

4

3 回答 3

2

让我们看看这个部分

    if(speed)    
        _oldShow.apply(obj, [speed,newCallback]);
    else    
        _oldShow.apply(obj, [newCallback]);

    });

_oldShow像之前一样被分配$.fn.show;,并.apply()调用一个带有参数的函数作为一个数组,并且能够设置this. (看这里)

所以,在函数结束时,我们总是会再次调用该函数,无限触发 beforeShow。

于 2012-05-22T16:02:48.577 回答
1

查看显示功能代码(在警报中):http: //jsfiddle.net/D9vP6/4/

它似乎在某种情况下呼唤自己,以使争论正常化。重新定义此函数后,您将收到无限递归。

为了避免这种行为,您应该在代码中进行所有这些规范化,并且在某些情况下不要触发事件。

于 2012-05-22T16:04:38.817 回答
1

上面代码的问题是,在某些时候 jQuery 调用了$.fn.showfrom 本身并创建了无限循环。因此,防止这种情况的正确方法是进行一些参数检查,如下所示:

 jQuery(function($) {
    var _oldShow = $.fn.show;
    $.fn.show = function(speed, easing, oldCallback) {

        var args = Array.prototype.slice.call(arguments),
            duration = args[0] || 0,
            easing = 'linear',
            callback = function() {},
            callbackArgIndex = 1;

        // jQuery recursively calls show sometimes; we shouldn't
        //  handle such situations. Pass it to original show method.    
        if (!this.selector) {
            _oldShow.apply(this, args);
            return this;
        }

        if (args.length === 2) {
            if ($.isFunction(args[1])) {
                callback = args[1];
                callbackArgIndex = 1;
            }
            else {
                easing = args[1];
            }
        }
        else if (args.length === 3) {
            easing = args[1];
            callback = args[2];
            callbackArgIndex = 2;
        }

        return this.each(function() {
            var obj = $(this),
                oldCallback = callback,
                newCallback = function() {

                    if ($.isFunction(oldCallback)) {
                        oldCallback.apply(obj);
                    }
                    obj.trigger('afterShow');
                };
            obj.trigger('beforeShow');
            args[0] = duration;

            if (callback) {
                args[callbackArgIndex] = newCallback;
            }
            else {
                args.push(callback);
            }

            _oldShow.apply(obj, args);


        });
    }
});


$('#dataBox').bind('beforeShow afterShow', function(e) {
    alert(e.type);
});


$('#toggleButton').click(function() {

    $('#dataBox').show();

});​

这工作正常,事件被正确触发。

阻止无限循环的块是这个

if (!this.selector) {
      _oldShow.apply(this, args);
      return this;
}

这样做是调用原始函数并在 jQuery$.fn.show多次调用的情况下返回(jQuery 似乎出于某种原因这样做)。

工作小提琴

于 2012-05-29T17:00:25.837 回答