如何确保Twitter引导程序弹出窗口可见?

Ste*_*ham 17 javascript twitter-bootstrap bootstrap-popover

有没有人知道twitter bootstrap的popover组件的扩展,它会动态更改placement位置以确保弹出窗口显示在屏幕上?

Cym*_*men 24

展示位置可以是函数而不是字符串.由fat编写然后移植到wleeper的最新版bootstrap 的自动放置的一个例子是这个项目的github问题之一:https://github.com/twitter/bootstrap/issues/345

以下是将CoffeeScript编译为JavaScript的结果:

$("a[rel=popover]").popover({
  placement: function(tip, element) {
    var $element, above, actualHeight, actualWidth, below, boundBottom, boundLeft, boundRight, boundTop, elementAbove, elementBelow, elementLeft, elementRight, isWithinBounds, left, pos, right;
    isWithinBounds = function(elementPosition) {
      return boundTop < elementPosition.top && boundLeft < elementPosition.left && boundRight > (elementPosition.left + actualWidth) && boundBottom > (elementPosition.top + actualHeight);
    };
    $element = $(element);
    pos = $.extend({}, $element.offset(), {
      width: element.offsetWidth,
      height: element.offsetHeight
    });
    actualWidth = 283;
    actualHeight = 117;
    boundTop = $(document).scrollTop();
    boundLeft = $(document).scrollLeft();
    boundRight = boundLeft + $(window).width();
    boundBottom = boundTop + $(window).height();
    elementAbove = {
      top: pos.top - actualHeight,
      left: pos.left + pos.width / 2 - actualWidth / 2
    };
    elementBelow = {
      top: pos.top + pos.height,
      left: pos.left + pos.width / 2 - actualWidth / 2
    };
    elementLeft = {
      top: pos.top + pos.height / 2 - actualHeight / 2,
      left: pos.left - actualWidth
    };
    elementRight = {
      top: pos.top + pos.height / 2 - actualHeight / 2,
      left: pos.left + pos.width
    };
    above = isWithinBounds(elementAbove);
    below = isWithinBounds(elementBelow);
    left = isWithinBounds(elementLeft);
    right = isWithinBounds(elementRight);
    if (above) {
      return "top";
    } else {
      if (below) {
        return "bottom";
      } else {
        if (left) {
          return "left";
        } else {
          if (right) {
            return "right";
          } else {
            return "right";
          }
        }
      }
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

除了一个案例之外,它对我来说效果很好:如果项目位于右上角,则弹出窗口没有好处,这是其中一个选项,它部分显示在屏幕上.

  • 这是一个很好的答案,但并不能完全解决问题.工具提示的宽度和高度在`actualWidth`和`actualHeight`中进行了硬编码,并且在渲染之前无法动态获取工具提示的大小. (4认同)

Chr*_*nes 13

对于那些对采用默认位置(使用data-placement元素属性)的解决方案感兴趣的人,我已经调整了Cymen的优秀答案.

我还确保不会不必要地计算边界,因此应该稍微提高性能.

$('[data-toggle="popover"]').each(function() {
    var trigger = $(this);
    trigger.popover({
        animation: true,
        delay: { show: 0, hide: 0 },
        html: true,
        trigger: 'hover focus',
        placement: getPlacementFunction(trigger.attr("data-placement"), 283, 117)
    });
});

var getPlacementFunction = function (defaultPosition, width, height) {
    return function (tip, element) {
        var position, top, bottom, left, right;

        var $element = $(element);
        var boundTop = $(document).scrollTop();
        var boundLeft = $(document).scrollLeft();
        var boundRight = boundLeft + $(window).width();
        var boundBottom = boundTop + $(window).height();

        var pos = $.extend({}, $element.offset(), {
            width: element.offsetWidth,
            height: element.offsetHeight
        });

        var isWithinBounds = function (elPos) {
            return boundTop < elPos.top && boundLeft < elPos.left && boundRight > (elPos.left + width) && boundBottom > (elPos.top + height);
        };

        var testTop = function () {
            if (top === false) return false;
            top = isWithinBounds({
                top: pos.top - height,
                left: pos.left + pos.width / 2 - width / 2
            });
            return top ? "top" : false;
        };

        var testBottom = function () {
            if (bottom === false) return false;
            bottom = isWithinBounds({
                top: pos.top + pos.height,
                left: pos.left + pos.width / 2 - width / 2
            });
            return bottom ? "bottom" : false;
        };

        var testLeft = function () {
            if (left === false) return false;
            left = isWithinBounds({
                top: pos.top + pos.height / 2 - height / 2,
                left: pos.left - width
            });
            return left ? "left" : false;
        };

        var testRight = function () {
            if (right === false) return false;
            right = isWithinBounds({
                top: pos.top + pos.height / 2 - height / 2,
                left: pos.left + pos.width
            });
            return right ? "right" : false;
        };

        switch (defaultPosition) {
            case "top":
                if (position = testTop()) return position;
            case "bottom":
                if (position = testBottom()) return position;
            case "left":
                if (position = testLeft()) return position;
            case "right":
                if (position = testRight()) return position;
            default:
                if (position = testTop()) return position;
                if (position = testBottom()) return position;
                if (position = testLeft()) return position;
                if (position = testRight()) return position;
                return defaultPosition;
        }
    }
};
Run Code Online (Sandbox Code Playgroud)