2014-02-16 172 views
1

我目前有一個我寫的jQuery工具提示插件的代碼如下。我使用jQuery的.data()方法爲每個工具提示存儲配置。但是,當我去檢索數據時,它被來自完全不同選擇器的最近存儲的數據覆蓋。我無法弄清這個問題,因爲它事先工作,然後突然停止。要查看的主要區域是addTooltip(),removeTooltip()和displayTooltip()。jQuery .data()被覆蓋

實施例:

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

然而,在我選擇兩個完全不同的元件,當我顯示它將使用#tooltip2的config的#tooltip1工具提示在這種情況下是「方向」上面的例子:「左」。

任何幫助表示讚賞。

(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)); 

回答

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/

0

把配置的聲明中的每個循環中

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

否則每個要素數據的配置將會引用一個配置對象,而當你改變它的變化將是由每個參考文獻可見。

您還可以再次使用擴展方法,使配置

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

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

我試過了,它沒有解決問題。如果您可以再次瀏覽一遍,我還將我的解釋更新爲更確切的問題。 –