如何覆盖JQuery的.show()和.hide()来触发事件之前和之后的事件?

时间:2012-05-22 12:39:14

标签: jquery callback override

我尝试覆盖JQuery的.show和.hide方法,以便在使用以下代码调用它们之前和之后启动触发器事件。

$(document).ready(function () {
    $('#dataBox').bind('afterShow', function () {
        alert('afterShow');
    });
    $('#dataBox').bind('afterHide', function () {
        alert('afterHide');
    });
    $('#dataBox').bind('beforeShow', function () {
        alert('beforeShow');
    });
    $('#dataBox').bind('beforeHide', function () {
        alert('beforeHide');
    });
    $('#toggleButton').click(function(){
        if($('#dataBox').is(':visible')) {
            $('#dataBox').hide ();
        } else {
            $('#dataBox').show();
        }
    });
});

jQuery(function ($) {
    var _oldShow = $.fn.show;
    //Override jquery's 'show()' method to include two triggered events before and after
    $.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');
            _oldShow.apply(obj, [speed, newCallback]);
        });
    }
});

jQuery(function ($) {
    var _oldHide = $.fn.hide;
    //Override jquery's 'hide()' method to include two triggered events before and after
    $.fn.hide = function (speed, oldCallback) {
        return $(this).each(function () {
            var obj = $(this),
                newCallback = function () {
                    if ($.isFunction(oldCallback)) {
                        oldCallback.apply(obj);
                }
                obj.trigger('afterHide');
            };
        obj.trigger('beforeHide');
            _oldHide.apply(obj, [speed, newCallback]);
        });
    }
});

我有以下标记:

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

当我点击切换按钮时,'beforeHide'和'beforeShow'事件正在触发,而'afterShow'和'afterHide'则没有。谁能让我知道我做错了什么?

3 个答案:

答案 0 :(得分:6)

检查demo fiddle。希望它有效

$。show / $ .hide - 覆盖功能:

(function($){
$.override ={'show': $.fn.show, 'hide': $.fn.hide};

$.each($.override,function(M,F){

        var m=M.replace( /^\w/, function(r){ return r.toUpperCase(); });

        $.fn[M] = function(speed, easing, callback) {

            var args=[speed||0,easing||'',callback||function(){}];

            if( $.isFunction(speed)){
                args[2]=speed;
                args[0]=0;
            }                   
            else if( $.isFunction(easing)){
                args[2]=easing;
                args[1]='';
            }                   

            if(!this.selector){
                F.apply(this, arguments);
                return this;
            }

            return this.each(function () {
                var obj = $(this),
                    oldCallback = args[args.length-1],
                    newCallback = function () {
                        if ($.isFunction(oldCallback)){
                            oldCallback.apply(obj);
                        }
                        obj.trigger('after'+m);
                };

                obj.trigger('before'+m);
                args[args.length-1]=newCallback;

                //alert(args);
                F.apply(obj,args);

            });
        }
});
})(jQuery);

<强>使用

jQuery(function($){
var $dataBox=$('#dataBox').bind('beforeHide afterHide beforeShow afterShow', function(e) {
    alert(e.type);
});

$('#toggleButton').bind('click',function(){
    $dataBox[$dataBox.is(':visible')?'hide':'show'](100,'swing',function(){ alert('end of animation');});
    return false;
});
});

答案 1 :(得分:3)

我在您的代码中设置了一些断点,并且发现您永远不会调用newCallback函数。多数民众赞成我认为,因为你在调用该函数时没有使用速度参数。 从jQuery原始函数的文档$.show可以看出,您可以使用$.shownoone或“三个参数”来调用two

  

.show(duration [,callback])

     

duration一个字符串或数字,用于确定动画运行的时间。

     

callbackA动画完成后调用的函数。

     

版本添加:1.4.3

     

.show([duration] [,easing] [,callback])

     

duration一个字符串或数字,用于确定动画运行的时间。

     

easing一个字符串,指示要用于转换的缓动函数。

     

callbackA动画完成后调用的函数。

所以你可能会或可能不会传递一堆不同的参数。所以我认为问题出在这一行

 _oldHide.apply(obj, [speed, newCallback]);

在此特定情况下,speed未定义。

您可以将$.fn.show功能称为

$(..).show(undefined,callBack)
//or
$(..).show(undefined,undefined, callBack)

如果没有指定其他参数,回调将始终必须是第一个参数,在这种情况下,jQuery将使用它的动画默认400ms速度/持续时间。你会看到一个fadeIn / fadeOut类型的效果。使其像使用此回调一样显示/隐藏

您必须致电_oldShow/_oldHide

_oldShow.apply(obj, [0,newCallback]);

//or

_oldHide.apply(obj, [0,newCallback]);

在快速搜索中,我在互联网上找到了一个代码,它似乎运行正常,并且可以对您传递给$.show$.hide的所有参数进行特殊处理。检查以下小提琴,看看

Working Fiddle

答案 2 :(得分:3)

为什么afterShowafterHide事件未被触发

如果显示/隐藏动画,jQuery将只调用代码中的回调函数(newCallback)。如果没有参数传递给.show() / .hide()(或speedundefined),那么jQuery将直接显示/隐藏元素,以及回调函数不会被执行。

为什么覆盖.show() / .hide()不是最好的主意

  • jQuery在内部调用.show() / .hide()(例如作为.fadeTo()的一部分)并递归调用(在进行动画显示/隐藏时),因此将触发自定义事件当你可能没想到他们的时候。

  • 恕我直言,最好将“股票”jQuery和自定义分开(作为插件),使用单独的方法名称/命名空间:

    • 当您的开发人员在http://api.jquery.com中查找库存方法时,他们会知道文档完整地描述了方法的行为。
    • 如果您的开发人员处理来自其他地方的代码,他们就不会调用股票方法,并期望特定于贵公司代码库的行为。

.eventedShow() / .eventedHide()

这会添加.eventedShow().eventedHide()(与.show() / .hide()采用相同的参数)并且应该按照您的意愿执行操作:

(function( $ ) {

$.each( [ 'Show', 'Hide' ], function( i, method ) {
    $.fn[ 'evented' + method ] = function( speed ) {
        var originalMethod = method.toLowerCase(),
            hasCallback = false,
            args;

        // animate
        if ( speed || speed === 0 ) {
            args = $.makeArray( arguments );
            $.each( args, function( i, arg ) {
                if ( $.isFunction( arg ) ) {
                    args[ i ] = function() {
                        arg.apply( this, arguments );
                        $( this ).trigger( 'after' + method );
                    };
                    hasCallback = true;
                    return false;
                }
            } );
            if ( !hasCallback ) {
                args.push( function() {
                    $( this ).trigger( 'after' + method );
                } );
            }

            this.each( function() {
                var el = $( this );
                el.queue( function() {
                    $( this )
                        .trigger( 'before' + method )
                        .dequeue();
                } );
                $.fn[ originalMethod ].apply( el, args );
            } );

        // straight show/hide
        } else {
            this.trigger( 'before' + method );
            $.fn[ originalMethod ].apply( this, arguments );
            this.trigger( 'after' + method );
        }

        return this;
    };
} );

})( jQuery );

您可以在此处尝试代码:http://jsfiddle.net/jefferyto/bv8D2/

您仍需要在现有代码中将show / hide更改为eventedShow / eventedHide,但这可以通过全局搜索完成 - 并且 - 取代