Zmieniasz położenie popoverów Bootstrap na podstawie pozycji X popovera w stosunku do krawędzi okna?


83

Przeszukałem Internet daleko i szeroko i chociaż znalazłem ten post z przepełnieniem stosu jako wnikliwy Czy można zmienić pozycję wyskakujących okienek Bootstrap na podstawie szerokości ekranu? , nadal nie odpowiedział na moje pytanie, prawdopodobnie z powodu problemów ze zrozumieniem pozycji / przesunięcia.

Oto, co próbuję zrobić. Chcę, aby pozycja Popover w usłudze Twitter Bootstap była PRAWA, chyba że popover hotspotu zostanie umieszczony poza widocznym obszarem, a następnie chcę, aby był ustawiony w LEWO. Tworzę aplikację internetową na iPada, która ma hotspoty, kiedy naciskasz na hotspot, pojawiają się informacje, ale nie chcę, aby pojawiały się poza widocznym obszarem, gdy przewijanie w poziomie jest zablokowane.

Myślę, że to wyglądałoby tak:

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

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

Myśli? Dzięki!

Odpowiedzi:


177

Właśnie zauważyłem, że opcja umieszczania może być ciągiem znaków lub funkcją zwracającą ciąg, który dokonuje obliczeń za każdym razem, gdy klikniesz łącze, które można wyświetlić.

Dzięki temu replikacja tego, co zrobiłeś bez początkowej funkcji $ .each, jest naprawdę łatwa :

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

1
To najlepszy sposób, ponieważ autonie zawsze działa idealnie w zależności od układu strony i treści, które umieścisz w wyskakującym okienku.
Bron Davies

Dzięki za to. Czy jest w porządku, jeśli używamy go bez przypisywania Tobie?
D.Tate

6
@ D. Tate Uważam, że wszystko na stackoverflow powinno być użyteczne bez przypisywania udziału.
Oszalej

3
Jaka jest logika wyboru left 515&top 110
Murali Murugesan

1
@MuraliMurugesan w ogóle nie ma logiki; Użyłem tylko liczb podanych w pytaniu. Możesz użyć wszystkiego, co chcesz.
bchhun

35

W przypadku Bootstrap 3 jest

placement: 'auto right'

co jest łatwiejsze. Domyślnie będzie to prawe, ale jeśli element znajduje się po prawej stronie ekranu, popover pozostanie. Więc powinno być:

$('.infopoint').popover({
   trigger:'hover',
   animation: false,
   placement: 'auto right'
});

2
Jak dotąd miałem z tym mieszane doświadczenia. Nie patrzyłem jeszcze na źródło Bootstrap, ale wygląda na to, że bierze pod uwagę tylko pozycjonowanie elementu, a nie przyszłą pozycję popover. Tak więc elementy, które znajdują się na krawędzi lub poza krawędzią okna, otrzymują co najwyżej popover na krawędzi, ale elementy, które znajdują się tuż nad krawędzią (na przykład), otrzymują popover poniżej zakładki.
Daved

1
Nie, to nie powinna być akceptowana odpowiedź. Opcja „umieszczenie” nie uwzględnia krawędzi okna , a jedynie granice elementu nadrzędnego / kontenera. Więc jeśli masz np. „Auto top”, będzie ono nadal wyświetlane w oknie top off po przewinięciu w dół.
rzb

31

Na podstawie dokumentacji powinieneś być w stanie użyć autow połączeniu z preferowanym miejscem docelowym, npauto left

http://getbootstrap.com/javascript/#popovers : „Po określeniu„ auto ”dynamicznie zmieni orientację okna popover. Na przykład, jeśli umieszczenie jest ustawione na„ automatycznie w lewo ”, etykietka zostanie wyświetlona w lewo, jeśli to możliwe, w przeciwnym razie wyświetli się po prawej ”.

Próbowałem zrobić to samo, a potem zdałem sobie sprawę, że ta funkcja już istnieje.


2
auto left daje poziomy pasek przewijania
Jitendra Vyas

3
Możesz również określić, viewportjeśli nie chcesz, aby był obliczany na podstawie elementu nadrzędnego elementu.
allicarn

5

Więc wymyśliłem sposób, aby zrobić to skutecznie. Na potrzeby mojego konkretnego projektu tworzę witrynę na iPada, więc dokładnie wiedziałem, jaka będzie wartość piksela X / Y, aby osiągnąć krawędź ekranu. Twoje wartości thisX i thisY będą się różnić.

Ponieważ popover i tak jest umieszczany za pomocą stylu wbudowanego, po prostu chwytam lewą i górną wartość dla każdego linku, aby zdecydować, w którym kierunku powinno być popover. Odbywa się to poprzez dołączenie wartości danych html5, których .popover () używa podczas wykonywania.

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

Wszelkie komentarze / ulepszenia są mile widziane, ale można to zrobić, jeśli chcesz ręcznie wprowadzić wartości.


2

Odpowiedź bchhun zaprowadziła mnie na właściwą ścieżkę, ale chciałem sprawdzić rzeczywistą przestrzeń dostępną między źródłem a krawędzią widoku. Chciałem również uszanować atrybut umieszczania danych jako preferencji z odpowiednimi rezerwami, jeśli nie było wystarczającej ilości miejsca. W ten sposób „w prawo” zawsze będzie przebiegać w prawo, chyba że na przykład nie było wystarczająco dużo miejsca, aby popover był wyświetlany po prawej stronie. Tak sobie z tym radziłem. U mnie to działa, ale wydaje się trochę uciążliwe. Jeśli ktoś ma jakieś pomysły na czystsze, bardziej zwięzłe rozwiązanie, byłbym zainteresowany.

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

1

Możesz też spróbować tego,

==> Uzyskaj pozycję docelową / źródłową w widoku
==> Sprawdź, czy przestrzeń od dołu jest mniejsza niż wysokość etykiety narzędzia
==> Jeśli przestrzeń od dołu jest mniejsza niż wysokość etykiety, po prostu przewiń stronę w górę

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";
}

0

Możesz użyć auto w rozmieszczaniu danych, na przykład data-placement = "auto left". Automatycznie dostosuje się do rozmiaru ekranu i pozostanie domyślne położenie.


0

Oprócz świetnej odpowiedzi bchhun, jeśli chcesz pozycjonować absoulte, możesz to zrobić

var options = {
    placement: function (context, source) {
         setTimeout(function () {
               $(context).css('top',(source.getBoundingClientRect().top+ 500) + 'px')
         },0)
         return "top";
    },
    trigger: "click"
};
$(".infopoint").popover(options);

0

Rozwiązałem swój problem w AngularJS w następujący sposób:

var configPopOver = {
        animation: 500,
        container: 'body',
        placement: function (context, source) {
                    var elBounding = source.getBoundingClientRect();
                    var pageWidth = angular.element('body')[0].clientWidth
                    var pageHeith = angular.element('body')[0].clientHeith

                    if (elBounding.left > (pageWidth*0.34) && elBounding.width < (pageWidth*0.67)) {
                        return "left";
                    }

                    if (elBounding.left < (pageWidth*0.34) && elBounding.width < (pageWidth*0.67)) {
                        return "right";
                    }

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

                    return "top";
                },
        html: true
    };

Ta funkcja ustawia pozycję pływającego popover Bootstrap do najlepszej pozycji na podstawie pozycji elementu.


0
$scope.popoverPostion = function(event){
    $scope.pos = '';

       if(event.x <= 207 && event.x >= 140){
           $scope.pos = 'top';
           event.x = '';
       }
       else if(event.x < 140){
           $scope.pos = 'top-left';
           event.x = '';
       }
       else if(event.x > 207){
           $scope.pos = 'top-right';
           event.x = '';
       }

};

-2

Możesz także wypróbować ten, jeśli potrzebujesz go w prawie wszystkich miejscach na stronie.

Możesz go skonfigurować w ogólny sposób, a następnie po prostu go użyć.

W ten sposób możesz również użyć elementu HTML i wszystkiego, co chcesz :)

$(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>

Dodanie


Aby ustawić więcej opcji, możesz przejść tutaj .

Jeszcze więcej można znaleźć tutaj .

Aktualizacja


Jeśli chcesz, aby wyskakujące okienko po kliknięciu, możesz zmienić opcję JS na trigger: "click"to-

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

Możesz również dostosować go w reklamach HTML, data-trigger="click"takich jak ta-

<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>

Myślę, że będzie to bardziej zorientowany kod, bardziej nadający się do ponownego wykorzystania i bardziej pomocny dla wszystkich :).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.