【问题标题】:Workaround for Bootstrap tooltip in multiple-line links多行链接中引导工具提示的解决方法
【发布时间】:2016-04-13 09:38:42
【问题描述】:

我知道在official Bootstrap page 中它说white-space: nowrap; 应该添加到带有工具提示的多行链接中。

但是,我正在开发一个 Chrome 扩展程序,我想在任何网页上添加工具提示,而不更改其原始布局。因此,建议的解决方案对我来说并不理想。

我尝试手动设置工具提示的位置。发生这种情况时,它将返回最左边的位置。所以,我尝试了this solution,它返回了正确的位置(链接的开头,而不是最左边的位置)。

问题是,无论是我设置了位置left 还是right,它都不会按照我的意愿定位。如果设置为right,它会显示在窗口之外,因为它从最右边的位置开始。如果设置为left,它也会显示在窗口外,因为它位于最左边的位置。

See Fiddle

在这种情况下,理想情况下,我希望将其放置在链接起点的左侧(在第一行)。

是否有解决方法来实现这一点?

【问题讨论】:

    标签: javascript jquery twitter-bootstrap tooltip twitter-bootstrap-tooltip


    【解决方案1】:

    您可以使用鼠标位置作为工具提示锚点,也可以修改工具提示 JavaScript 代码以实现此目的,如 How to make popover appear where my mouse enters the hover target? 中所示。您可以将底部代码与链接中的代码合并以实现两者并选择您喜欢的代码。

    在 bootstrap-tooltip.js 中,替换(我认为是第 1602 行)(抱歉格式不佳)

     Tooltip.prototype.getPosition 
     and
     Tooltip.prototype.getCalculatedOffset
    

    函数分别

    Tooltip.prototype.getPosition = function($element) {
      $element = $element || this.$element
    
      var el = $element[0]
      var isBody = el.tagName == 'BODY'
    
      var elRect = el.getBoundingClientRect()
      if (elRect.width == null) {
        // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
        elRect = $.extend({}, elRect, {
          width: elRect.right - elRect.left,
          height: elRect.bottom - elRect.top
        })
      }
    
      var rects = el.getClientRects();
      var firstRect = rects[0];
      var lastRect = rects[rects.length - 1];
    
      firstRect = $.extend({}, firstRect, {
        width: firstRect.right - firstRect.left,
        height: firstRect.bottom - firstRect.top
      })
      lastRect = $.extend({}, lastRect, {
        width: lastRect.right - lastRect.left,
        height: lastRect.bottom - lastRect.top
      })
    
    
    
      var elOffset = isBody ? {
        top: 0,
        left: 0
      } : $element.offset()
      var elScrollTop = elOffset.top - elRect.top;
      var elScrollLeft = elOffset.left - elRect.left;
      firstRect.top += elScrollTop;
      lastRect.top += elScrollTop;
      firstRect.left += elScrollLeft;
      lastRect.left += elScrollLeft;
    
      firstRect = {
        firstRect: firstRect
      };
      lastRect = {
        lastRect: lastRect
      };
    
      var scroll = {
        scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop()
      }
      var outerDims = isBody ? {
        width: $(window).width(),
        height: $(window).height()
      } : null
    
      return $.extend({}, elRect, scroll, outerDims, elOffset, firstRect, lastRect)
    }
    
    Tooltip.prototype.getCalculatedOffset = function(placement, pos, actualWidth, actualHeight) {
      return placement == 'bottom' ? {
          top: pos.top + pos.height,
          left: pos.left + pos.width / 2 - actualWidth / 2
        } :
        placement == 'top' ? {
          top: pos.top - actualHeight,
          left: pos.left + pos.width / 2 - actualWidth / 2
        } :
        placement == 'left' ? {
          top: pos.top + pos.height / 2 - actualHeight / 2,
          left: pos.left - actualWidth
        } :
        placement == 'textleft' ? {
          top: pos.firstRect.top + (pos.firstRect.height / 2) - actualHeight / 2,
          left: pos.firstRect.left - actualWidth
        } :
        placement == 'textright' ? {
          top: pos.lastRect.top + (pos.lastRect.height / 2) - actualHeight / 2,
          left: pos.lastRect.right
        } :
        /* placement == 'right' */
        {
          top: pos.top + pos.height / 2 - actualHeight / 2,
          left: pos.left + pos.width
        }
    }
    

    现在您可以使用展示位置“textleft”和“textright”。 这适用于 Bootstrap v3.3.6。可以通过不直接编辑引导源而是对其进行扩展来改进它(而且有点脏)。

    您还需要将此添加到 css 中以获得工具提示箭头。

    .tooltip.textright {
      padding: 0 5px;
      margin-left: 3px;
    }
    .tooltip.textleft {
      padding: 0 5px;
      margin-left: -3px;
    }
    
    .tooltip.textleft .tooltip-arrow{
      top: 50%;
      right: 0;
      margin-top: -5px;
      border-width: 5px 0 5px 5px;
      border-left-color: #000;
    }
    
    .tooltip.textright .tooltip-arrow{
      top: 50%;
      left: 0;
      margin-top: -5px;
      border-width: 5px 5px 5px 0;
      border-right-color: #000;
    }
    

    这里是小提琴:JSFiddle

    【讨论】:

    • 感谢您指出至少要遵循的方向。我一直在尝试这个(虽然在 Bootstrap v3.3.6 中),但我想这还不是解决方案。这只会改变工具提示初始位置(上、左)的位置,但不会改变工具提示位置是left 还是right。所以,工具提示一直试图向右移动,走出窗口。鼠标的想法也不错,但由于工具提示显示有延迟,它看起来很糟糕,因为位置是您第一次悬停元素时的位置。
    • 似乎 Bootstrap v3.3.6 和 v2.x.x 在源代码上有很大的不同。我已经添加了最新版本的代码。
    • 不错!我昨天尝试时忘记了 CSS 部分,你的更改看起来也比我的更有条理。正如我在问题中所说,我仍在努力放置textlefttextright,具体取决于用户是悬停在上线还是底线,所以它看起来好多了。我应该编辑你的答案吗?
    • 它应该看起来好多了,就像你说的那样。随时进行更改。
    • 我认为getClientRects 有问题。如果您调整窗口大小(在 JSFiddle 中,您需要将其设置得非常小,因为输出窗口也很小),textrighttextleft 工具提示会显示在错误的位置,具体取决于您向下/向上滚动的程度。你能想出一个解决办法吗?
    【解决方案2】:

    这是对@Gökhan Kurt 答案的改进。

    他的解决方案将工具提示放置在多行链接的左侧或右侧。但是,我想改进它并使它看起来更好。因此,当您将鼠标悬停在上一行时,工具提示会出现在链接的左侧;当您将鼠标悬停在底线时,工具提示会出现在链接的右侧。

    为此,我检测用户悬停链接的位置。如果它靠近窗口的右侧,则表示它是上线。否则,这是底线。如果您在工具提示选项中设置container: 'body',这将有效。

    Bootstrap v3.3.6,tooltip插件源码:

    enter函数中获取鼠标位置:

    if (obj instanceof $.Event) {
      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
      var mousePos = { x: -1, y: -1 };
      mousePos.x = obj.pageX;
      mousePos.y = obj.pageY;
      window.mousePos = mousePos;
    }
    

    show函数中清除placement CSS类(因为每次悬停链接时可能不同)并根据鼠标位置设置新的placement:

    var isTextPlacement = /textleft|textright/.test(placement)
    if(isTextPlacement){
        $tip.removeClass("textright");
        $tip.removeClass("textleft");
    }
    
    //390 is hardcoded value which is the max size of the tooltip, you may adjust to your case
    if(placement == 'textleft' && window.mousePos.x < 390){
      placement = 'textright';
    }else if(placement == 'textright' && window.mousePos.x > $(window).width() - 390){
      placement = 'textleft';
    }
    

    对于getCalculatedOffset,我使用了以下内容,如果无法应用textright,则应用textleft

      Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
        var windowWidth = $(window).width();
    
        return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
               placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
               placement=='left'?{ top: pos.top+pos.height/2-actualHeight/2, left: pos.left-actualWidth }:
               placement == 'right' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } :
               placement=='textleft' && window.mousePos.x > 390 ? { top: pos.firstRect.top+(pos.firstRect.height/2)-actualHeight/2, left: pos.firstRect.left-actualWidth }:
               /*placement=='textright'*/ window.mousePos.x < windowWidth - 390 ? { top: pos.lastRect.top+(pos.lastRect.height/2)-actualHeight/2, left: pos.lastRect.right }:
               /*apply textleft*/         { top: pos.firstRect.top+(pos.firstRect.height/2)-actualHeight/2, left: pos.firstRect.left-actualWidth }
      }
    

    就是这样。检查JSFiddle(调整输出窗口的大小以使链接跨越两行并与@Gökhan Kurt 答案进行比较。由于硬编码390px,您可能需要将其设置得更大)。

    【讨论】:

      猜你喜欢
      • 2017-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-15
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      相关资源
      最近更新 更多