Changing the position of Bootstrap popovers based

2020-01-24 10:23发布

I have scoured the Internet far and wide and while I found this stackoverflow post insightful Is it possible to change the position of Bootstrap popovers based on screen width?, it still didn't answer my question, likely due to my trouble understanding position/offset.

Here's what I'm trying to do. I want the Twitter Bootstap Popover position to be RIGHT unless the hotspot popover will be positioned beyond the viewport, then I want it to be positioned LEFT. I'm making an iPad web app that has hot spots, when you push on a hotspot, information appears but I don't want it to appear outside of the viewport when horizontal scrolling is locked.

I'm thinking it'd go something like this:

$('.infopoint').popover({
        trigger:'hover',
        animation: false,
        placement: wheretoplace 
    });
    function wheretoplace(){
        var myLeft = $(this).offset.left;

        if (myLeft<500) return 'left';
        return 'right';
    }

Thoughts? Thanks!

10条回答
疯言疯语
2楼-- · 2020-01-24 10:56

You can also try this one,

==> Get target/source position in viewport
==> Check whether space from bottom is less that your tooltip height
==> If space from bottom is less that your tooltip height, then just scroll page up

placement: function(context, source){
  //get target/source position in viewport
  var bounds = $(source)[0].getBoundingClientRect();
      winHeight = $(window).height();

  //check wheather space from bottom is less that your tooltip height
  var rBottom = winHeight - bounds.bottom;

  //Consider 180 == your Tooltip height
  //if space from bottom is less that your tooltip height, this will scrolls page up
  //We are keeping tooltip position is fixed(at bottom)

  if (rBottom < 180){
    $('html, body').animate({ scrollTop: $(document).scrollTop()+180 }, 'slow');
  }

  return "bottom";
}
查看更多
神经病院院长
3楼-- · 2020-01-24 10:57

I just noticed that the placement option could either be a string or a function returning a string that makes the calculation each time you click on a popover-able link.

This makes it real easy to replicate what you did without the initial $.each function:

var options = {
    placement: function (context, source) {
        var position = $(source).position();

        if (position.left > 515) {
            return "left";
        }

        if (position.left < 515) {
            return "right";
        }

        if (position.top < 110){
            return "bottom";
        }

        return "top";
    }
    , trigger: "click"
};
$(".infopoint").popover(options);
查看更多
▲ chillily
4楼-- · 2020-01-24 10:57

For Bootstrap 3, there is

placement: 'auto right'

which is easier. By default, it will be right, but if the element is located in the right side of the screen, the popover will be left. So it should be:

$('.infopoint').popover({
   trigger:'hover',
   animation: false,
   placement: 'auto right'
});
查看更多
爷、活的狠高调
5楼-- · 2020-01-24 10:58

So I figured out a way to do this effectively. For my particular project I'm building an iPad website so I knew exactly what the pixel X/Y value would be to reach the edge of the screen. Your thisX and thisY values will vary.

Since the popovers are being placed by inline styling anyway, I simply grab the left and top values for each link to decide which direction the popover should be. This is done by appending html5 data- values that .popover() uses upon execution.

if ($('.infopoint').length>0){
    $('.infopoint').each(function(){
        var thisX = $(this).css('left').replace('px','');
        var thisY = $(this).css('top').replace('px','');
        if (thisX > 515)
            $(this).attr('data-placement','left');
        if (thisX < 515)
            $(this).attr('data-placement','right');
        if (thisY > 480)
            $(this).attr('data-placement','top');
        if (thisY < 110)
            $(this).attr('data-placement','bottom');
    });
    $('.infopoint').popover({
        trigger:'hover',
        animation: false,
        html: true
    });
}

Any comments/improvements are welcome but this gets the job done if you're willing to put the values in manually.

查看更多
在下西门庆
6楼-- · 2020-01-24 11:01

You can also try this one if u need it in almost all places in the page.

U can configure it in a general way then just use it.

In this way u can also use HTML element and anything u want :)

$(document).ready(function()
                  {
  var options =
      {
        placement: function (context, source)
        {
          var position = $(source).position();
          var content_width = 515;  //Can be found from a JS function for more dynamic output
          var content_height = 110;  //Can be found from a JS function for more dynamic output

          if (position.left > content_width)
          {
            return "left";
          }

          if (position.left < content_width)
          {
            return "right";
          }

          if (position.top < content_height)
          {
            return "bottom";
          }

          return "top";
        }
        , trigger: "hover"
        , animation: "true"
        , html:"true"
      };
  $('[data-toggle="popover"]').popover(options);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>


<div class="container">
	<h3>Popover Example</h3>
	<a id="try_ppover" href="#" data-toggle="popover" title="Popover HTML Header" data-content="<div class='jumbotron'>Some HTML content inside the popover</div>">Toggle popover</a>
</div>

Addition


For setting more options, u can go here.

Even more can be found here.

Update


If u want the popup after click, u can change the JS option to trigger: "click" like this-

        return ..;
    }
    ......
    , trigger: "click"
    ......
};

U also can customize it in HTML ading data-trigger="click" like this-

<a id="try_ppover" href="#" data-toggle="popover" data-trigger="click" title="Popover Header" data-content="<div class='jumbotron'>Some content inside the popover</div>">Toggle popover</a>

I think it will be more oriented code and more re-usable and more helpful to all :).

查看更多
唯我独甜
7楼-- · 2020-01-24 11:03

bchhun's answer got me on the right track, but I wanted to check for actual space available between the source and the viewport edge. I also wanted to respect the data-placement attribute as a preference with appropriate fallbacks if there wasn't enough space. That way "right" would always go right unless there wasn't enough space for the popover to show on the right side, for example. This was the way I handled it. It works for me, but it feels a bit cumbersome. If anyone has any ideas for a cleaner, more concise solution, I'd be interested to see it.

var options = {
  placement: function (context, source) {
    var $win, $source, winWidth, popoverWidth, popoverHeight, offset, toRight, toLeft, placement, scrollTop;

    $win = $(window);
    $source = $(source);
    placement = $source.attr('data-placement');
    popoverWidth = 400;
    popoverHeight = 110;
    offset = $source.offset();

    // Check for horizontal positioning and try to use it.
    if (placement.match(/^right|left$/)) {
      winWidth = $win.width();
      toRight = winWidth - offset.left - source.offsetWidth;
      toLeft = offset.left;

      if (placement === 'left') {
        if (toLeft > popoverWidth) {
          return 'left';
        }
        else if (toRight > popoverWidth) {
          return 'right';
        }
      }
      else {
        if (toRight > popoverWidth) {
          return 'right';
        }
        else if (toLeft > popoverWidth) {
          return 'left';
        }
      }
    }

    // Handle vertical positioning.
    scrollTop = $win.scrollTop();
    if (placement === 'bottom') {
      if (($win.height() + scrollTop) - (offset.top + source.offsetHeight) > popoverHeight) {
        return 'bottom';
      }
      return 'top';
    }
    else {
      if (offset.top - scrollTop > popoverHeight) {
        return 'top';
      }
      return 'bottom';
    }
  },
  trigger: 'click'
};
$('.infopoint').popover(options);
查看更多
登录 后发表回答