jQuery .data()正在被覆盖

时间:2014-02-16 20:22:03

标签: javascript jquery tooltip

我目前有以下代码用于我正在编写的jQuery工具提示插件。我使用jQuery的.data()方法存储每个工具提示的配置。但是,当我去检索数据时,它已被完全不同的选择器中最近存储的数据覆盖。我无法弄清楚问题,因为它先前工作然后突然停止。要查看的主要区域是addTooltip(),removeTooltip()和displayTooltip()。

示例:

$('#tooltip1').addTooltip('tooltip', { 'direction': 'bottom' });
$('#tooltip2').addTooltip('tooltip', { 'direction': 'left' });

在上面的示例中,我选择了两个完全不同的元素,但是当我显示#tooltip1工具提示时,它将使用#tooltip2的配置,在这种情况下是'direction':'left'。

感谢任何帮助。

(function($) {

// Used as a template for addTooltip()
var tooltipDefaults = {
    'class': null,
    'showOn': 'mouseenter',
    'hideOn': 'mouseleave',
    'direction': 'top',
    'offset': 0
}

// Store generated IDs to avoid conflicting IDs
var tooltipIds = new Array();

// Keep track of displayed popups
var displayedTooltips = new Array();

function generateUniqueId()
{
    var id;

    do {
        id = Math.floor(Math.random()*90000) + 10000;
    } while ($.inArray(id, tooltipIds) !== -1);

    tooltipIds.push(id);
    return id;
}

function getUniqueId(id)
{
    return parseInt(id.substr(0, 5));
}

function isUniqueId(id)
{
    return !NaN(getUniqueId(id));
}

function removeUniqueId(id)
{
        var id = getUniqueId(id);

        var idIndex = $.inArray(id, tooltipIds);

        if (idIndex !== -1) {
            tooltipIds.splice(idIndex);
        }
}

$.fn.displayTooltip = function()
{
    var element = $(this);
    var tooltip = $('#' + element.attr('data-tooltip-id'));
    var config = element.data('config');

    var offset = element.offset();

    var left;   
    var top;

    switch (config.direction) {
        case 'left':
            top = offset.top + "px";
            left = offset.left - tooltip.outerWidth() - config.offset + "px";
            break;
        case 'top':
            top = offset.top - element.outerHeight() - config.offset + "px";
            left = offset.left + ((element.outerWidth() / 2) - (tooltip.outerWidth() / 2)) + "px";
            break;
        case 'right':
            top = offset.top + "px";
            left = offset.left + element.outerWidth() + config.offset + "px";
            break;
        case 'bottom':
            top = offset.top + element.outerHeight() + config.offset + "px";
            left = offset.left + ((element.outerWidth() / 2) - (tooltip.outerWidth() / 2)) + "px";
            break;
    }

    tooltip.css({
        'position': 'absolute',
        'left': left,
        'top': top,
        'z-index': 5000
    });

    if (element.isTooltipDisplayed()) {
        return;
    }

    tooltip.show();
    displayedTooltips.push(element.attr('id'));
}

$.fn.hideTooltip = function()
{
    var element = $(this);

    var idIndex = $.inArray(element.attr('id'), displayedTooltips);

    if (idIndex !== -1) {
        displayedTooltips.splice(idIndex);
    }

    $('#' + element.attr('data-tooltip-id')).hide();
}

$.fn.addTooltip = function(content, params)
{
    var config = $.extend(tooltipDefaults, params);

    return this.each(function() {
        var element = $(this);

        // If the element already has a tooltip change the content inside of it
        if (element.hasTooltip()) {
            $('#' + element.attr('data-tooltip-id')).html(content);
            return;
        }

        var tooltipId = (element.is('[id]') ? element.attr('id') : generateUniqueId()) + '-tooltip';
        element.attr('data-tooltip-id', tooltipId);

        var tooltip = $('<div>', {
            id: tooltipId,
            role: 'tooltip',
            class: config.class
        }).html(content);

        $('body').append(tooltip);

        /**
         * If showOn and hideOn are the same events bind a toggle
         * listener else bind the individual listeners
         */
        if (config.showOn === config.hideOn) {
            element.on(config.showOn, function() {
                if (!element.isTooltipDisplayed()) {
                    element.displayTooltip();
                } else {
                    element.hideTooltip();
                }
            });
        } else {
            element.on(config.showOn, function() {
                element.displayTooltip();
            }).on(config.hideOn, function() {
                element.hideTooltip();
            });
        }

        // Store config for other functions use
        element.data('config', config);

        // Saftey check incase the element recieved focus from the code running above
        element.hideTooltip();
    });
}

$.fn.hasTooltip = function()
{
    return $(this).is('[data-tooltip-id]');
}

$.fn.isTooltipDisplayed = function()
{
    var element = $(this);

    if (!element.hasTooltip()) {
        return false;
    }

    return ($.inArray(element.attr('id'), displayedTooltips) === -1) ? false : true;
}

$.fn.removeTooltip= function()
{
    return this.each(function() {
        var element = $(this);
        var tooltipId = element.attr('data-tooltip-id');
        var config = element.data('config');

        $('#' + tooltipId).remove();

        if (isUniqueId(tooltpId)) {
            removeUniqueId(tooltipId);
        }

        element.removeAttr('data-tooltip-id');

        if (config.showOn === config.hideOn) {
            element.off(config.showOn);
        } else {
            element.off(config.showOn);
            element.off(config.hideOn);
        }

        element.removeData('config');
    });
}

// Reposition tooltip on window resize
$(window).on('resize', function() {
    if (displayedTooltips.length < 1) {
        return;
    }

    for (var i = 0; i < displayedTooltips.length; i++) {
        $('#' + displayedTooltips[i]).displayTooltip();
        console.log(displayedTooltips);
    }
});
}(jQuery));

2 个答案:

答案 0 :(得分:0)

将config的声明放在每个循环中

return this.each(function() {
    var element = $(this);
    var config = $.extend(tooltipDefaults, params);
    ...

否则每个元素数据中的配置将引用该单个配置对象,当您更改它时,每个引用都会看到更改。

您还可以再次使用extend方法来复制config

var defConfig = $.extend(tooltipDefaults, params);

return this.each(function() {
    var element = $(this);
    var config = $.extend({}, defConfig);

答案 1 :(得分:0)

执行此操作时:

element.data('config', config);
每当我们致电时,

config都会有不必要的修改:

 var config = $.extend(tooltipDefaults, params);

此示例:http://jsfiddle.net/j8v4s/1/

您可以通过创建一个继承自tooltipDefaults的新对象来解决此问题,但在修改后,只会更改其自身。你可以使你的tooltipDefaults对象像这样的构造函数:

function TooltipDefaults() {
    this.class = null;
    this.showOn = 'mouseenter';
    this.hideOn = 'mouseleave';
    this.direction = 'top';
    this.offset = 0;
}

现在我们可以这样做:

var config = new TooltipDefaults();
$.extend(config, params);

示例:http://jsfiddle.net/sXSFy/4/

以下是您的插件的一个有效示例:http://jsfiddle.net/DWtL5/2/