jQuery插件搞乱AJAX结果

时间:2013-04-03 07:41:40

标签: javascript jquery ajax

我有一个函数可以在按键上调用AJAX,如果结果不为空,则将其置于工具提示中。如果我停用它,一切都按预期工作,但一旦启用,AJAX似乎在返回空变量和实际结果之间“切换”。

以下是进行AJAX调用并激活工具提示的部分:

jQuery(document).ready(function() {
    jQuery('.qty').keyup(function() {
        var qty   = jQuery(this).val();
        var pid = jQuery(this).next().html();
        var element = this;

        jQuery.post('shopping_cart_ajax.php', {products_id: pid, products_quantity: qty}, function(data) {
            if (data)
            {
                jQuery(element).tooltip();
                jQuery(element).unbind('mouseenter mouseleave');
                jQuery(element).tooltip('update', data);
                jQuery(element).tooltip('show');
            }
            else
            {
                jQuery(element).tooltip('destroy');
            }
        });
    });
});

插件本身:

(function($) {
var methods = {
    //създаване на tooltip-а
    init: function(options) {
        //настройки по подразбиране
        if (!options)
        {
            options = {
                method: "hover",    //метод за активация на tooltip-а по подразбиране (за момента има само hover опция)
                color: "#dc143c"    //цвят по подразбиране
            };
        }

        return this.each(function() {
            //намиране текста на tooltip-а
            var tooltip_text = $(this).attr("tooltip");

            //добавяне на тялото и стрелката
            $(this).after('<div></div>');
            $(this).after('<div class="tooltip_base">'+tooltip_text+'</div>');

            switch (options.method)
            {
                case "hover":
                    methods.hover(this, options.color);
                break;
            }
        });
    },

    //показване на tooltip-а при посочване с мишката
    hover: function(object, color) {
        $(object).hover(
            function() {
                methods.position(object, color);
                $(object).next().next().fadeIn();   //показване на стрелката
                $(object).next().fadeIn();          //показване на тялото
            },
            function() {
                $(object).next().next().hide();     //скриване на стрелката
                $(object).next().hide();            //скриване на тялото
            }
        );
    },

    //позициониране на tooltip-а
    position: function(object, color) {
        //намиране позицията на елемента, под който трябва да се появи tooltip-а
        var offset = $(object).offset();

        //намиране размерите на елемента
        var parent_width = $(object).outerWidth();
        var parent_height = $(object).outerHeight();

        //намиране размерите на tooltip-а
        var tooltip_width = $(object).next().outerWidth();
        var tooltip_height = $(object).next().outerHeight();

        //намиране вида на tooltip-а и начина на позициониране
        var pos_tooltip_top;
        var pos_tooltip_left;
        var pos_arrow_top;
        var pos_arrow_left;
        var arrow_type;

        if ($(object).hasClass("tooltip_top_center") == true)
        {
            pos_tooltip_top  = offset.top-tooltip_height-5;
            pos_tooltip_left = offset.left+(parent_width/2)-(tooltip_width/2);
            pos_arrow_top    = offset.top-5;
            pos_arrow_left   = offset.left+(parent_width/2)-5;
            arrow_type       = "tooltip_bottom_arrow";
        }
        else if ($(object).hasClass("tooltip_top_right") == true)
        {
            pos_tooltip_top  = offset.top-tooltip_height-5;
            pos_tooltip_left = offset.left+(parent_width/2)-12;
            pos_arrow_top    = offset.top-5;
            pos_arrow_left   = offset.left+(parent_width/2)-5;
            arrow_type       = "tooltip_bottom_arrow";
        }
        else if ($(object).hasClass("tooltip_top_left") == true)
        {
            pos_tooltip_top  = offset.top-tooltip_height-5;
            pos_tooltip_left = offset.left-tooltip_width+(parent_width/2)+12;
            pos_arrow_top    = offset.top-5;
            pos_arrow_left   = offset.left+(parent_width/2)-5;
            arrow_type       = "tooltip_bottom_arrow";
        }
        else if ($(object).hasClass("tooltip_bottom_center") == true)
        {
            pos_tooltip_top  = offset.top+parent_height+5;
            pos_tooltip_left = offset.left+(parent_width/2)-(tooltip_width/2);
            pos_arrow_top    = offset.top+parent_height;
            pos_arrow_left   = offset.left+parent_width/2-5;
            arrow_type       = "tooltip_top_arrow";
        }
        else if ($(object).hasClass("tooltip_bottom_right") == true)
        {
            pos_tooltip_top  = offset.top+parent_height+5;
            pos_tooltip_left = offset.left+(parent_width/2)-12;
            pos_arrow_top    = offset.top+parent_height;
            pos_arrow_left   = offset.left+parent_width/2-5;
            arrow_type       = "tooltip_top_arrow";
        }
        else if ($(object).hasClass("tooltip_bottom_left") == true)
        {
            pos_tooltip_top  = offset.top+parent_height+5;
            pos_tooltip_left = offset.left-tooltip_width+(parent_width/2)+12;
            pos_arrow_top    = offset.top+parent_height;
            pos_arrow_left   = offset.left+parent_width/2-5;
            arrow_type       = "tooltip_top_arrow";
        }
        else if ($(object).hasClass("tooltip_left") == true)
        {
            pos_tooltip_top  = offset.top-(tooltip_height/2)+(parent_height/2);
            pos_tooltip_left = offset.left-tooltip_width-5;
            pos_arrow_top    = offset.top-5+(parent_height/2);
            pos_arrow_left   = offset.left-5;
            arrow_type       = "tooltip_right_arrow";
        }
        else if ($(object).hasClass("tooltip_right") == true)
        {
            pos_tooltip_top  = offset.top-(tooltip_height/2)+(parent_height/2);
            pos_tooltip_left = offset.left+parent_width+5;
            pos_arrow_top    = offset.top-5+(parent_height/2);
            pos_arrow_left   = offset.left+parent_width;
            arrow_type       = "tooltip_left_arrow";
        }
        else
        {
            pos_tooltip_top  = offset.top+parent_height+3;
            pos_tooltip_left = offset.left+(parent_width/2)-(tooltip_width/2);
            arrow_type       = "tooltip_no_arrow";
        }

        //позициониране на тялото
        $(object).next().css({
            "top": pos_tooltip_top,
            "left": pos_tooltip_left
        });

        //избиране на подходящата стрелка
        $(object).next().next().addClass(arrow_type);

        //позициониране на стрелката
        $(object).next().next().css({
            "top": pos_arrow_top,
            "left": pos_arrow_left
        });

        if (color != "")
        {
            //задаване цвят на тялото
            $(object).next().css({
                "background-color": color
            });

            var tooltip_class = $(object).next().next().attr("class");
            var arrow_color;

            //задаване цвят на стрелката
            switch (tooltip_class)
            {
                case "tooltip_top_arrow":
                    arrow_color = "transparent transparent "+color+" transparent";
                break;

                case "tooltip_bottom_arrow":
                    arrow_color = color+" transparent transparent transparent";
                break;

                case "tooltip_left_arrow":
                    arrow_color = "transparent "+color+" transparent transparent";
                break;

                case "tooltip_right_arrow":
                    arrow_color = "transparent transparent transparent "+color;
                break;
            }

            $(object).next().next().css({
                "border-color": arrow_color
            });
        }
    },

    //показване
    show: function() {
        $(this).next().next().fadeIn();     //показване на стрелката
        $(this).next().fadeIn();            //показване на тялото
    },

    //скриване
    hide: function() {
        $(this).next().next().hide();       //скриване на стрелката
        $(this).next().hide();              //скриване на тялото
    },

    //промяна на съдържанието на tooltip-а
    update: function(content, color) {
        if (!color)
        {
            color = "#dc143c";
        }

        $(this).attr({
            "tooltip": content
        });

        $(this).next().html(content);

        methods.position(this, color);
    },

    //изтриване на tooltip-а
    destroy: function() {
        if ($(this).next().hasClass('tooltip_base'))
        {
            $(this).removeAttr('tooltip');
            $(this).next().next().remove();
            $(this).next().remove();
            $(this).unbind('mouseenter mouseleave');
        }
    }
};

$.fn.tooltip = function(method) {
    if (methods[method])
    {
        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    }
    else if (typeof method === 'object' || !method)
    {
        return methods.init.apply(this, arguments);
    }
    else
    {
        $.error('Method '+method+' does not exist on jQuery.tooltip');
    }
};
})(jQuery);

1 个答案:

答案 0 :(得分:2)

我认为您的插件与您所看到的问题无关。

您的代码会在每次按键时启动Ajax调用

因此,在多次击键时,您接着会一个接一个地接收多个响应,其中一些可能是空的,也可能不是空的,这解释了您所看到的“切换”效果。

我认为你真正想要的只是在用户停止输入后才处理最终的Ajax 。或者换句话说,在任何给定时间内,“每个目的”应该只有一个活动的Ajax请求。

因此,您需要引用初始Ajax调用,并在随后的击键中将其中止,然后启动一个新的。

jQuery(document).ready(function() {

    var xhr;

    jQuery('.qty').keyup(function() {
        var qty   = jQuery(this).val();
        var pid = jQuery(this).next().html();
        var element = this;

        // abort the Ajax request invoked by previous keystrokes
        if (xhr) xhr.abort();

        xhr = jQuery.post('shopping_cart_ajax.php', {products_id: pid, products_quantity: qty}, function(data) {
            if (data)
            {
                jQuery(element).tooltip();
                jQuery(element).unbind('mouseenter mouseleave');
                jQuery(element).tooltip('update', data);
                jQuery(element).tooltip('show');
            }
            else
            {
                jQuery(element).tooltip('destroy');
            }
        });
    });
});

供您参考,.post()会返回jqXHR对象(http://api.jquery.com/jQuery.post/),该对象会公开abort()方法(http://api.jquery.com/jQuery.ajax/#jqXHR)

对于Ajax调用,尤其是那些通过悬停或在你的情况下通过键盘调用的调用,这是我一直记住的那种例程:即中止以前的Ajax调用。