Jak pozycjonować jeden element względem drugiego za pomocą jQuery?

354

Mam ukryty DIV, który zawiera menu podobne do paska narzędzi.

Mam kilka DIV, które są włączone, aby pokazywać DIV menu, gdy kursor myszy nad nimi unosi się.

Czy jest wbudowana funkcja, która przeniesie menu DIV do prawego górnego rogu aktywnego DIV (najechanie myszą)? Szukam czegoś takiego$(menu).position("topright", targetEl);

Paweł
źródło
1
spójrz na stackoverflow.com/questions/8400876/..., który rozwiązuje wiele innych problemów, które mogą wystąpić
Toskan
Zobacz „Czy pytania powinny zawierać„ tagi ”w tytułach?” , gdzie konsensus brzmi „nie, nie powinni”!
Andreas Niedermair,
@paul Tak, istnieje niewielka różnica w stylu. Początkowy tytuł tego pytania był poprzedzony jQuery:, co nie jest zalecane. Zwykle z powodu dodatkowego otagowania pytania, co sprawia, że ​​prefiksowanie jest bezużyteczne. Jeśli technologia jest potrzebna w tytule, powinna zostać uchwycona w prawdziwym zdaniu, a nie tylko przedrostku - ponieważ po to są tagi.
Andreas Niedermair,

Odpowiedzi:

203

UWAGA: Wymaga to interfejsu użytkownika jQuery (nie tylko jQuery).

Możesz teraz użyć:

$("#my_div").position({
    my:        "left top",
    at:        "left bottom",
    of:        this, // or $("#otherdiv")
    collision: "fit"
});

Do szybkiego pozycjonowania ( jQuery UI / Position ).

Możesz pobrać jQuery UI tutaj .

Uriel
źródło
1
Próbowałem użyć wtyczki positon, ale z jakiegoś powodu po prostu nie mogę jej uruchomić :(
Salman A
Też nie działa dla mnie. Próba użycia tego do umieszczenia prostego div jednolitego koloru nad ciałem spowodowała, że ​​był on wyłączony o 17 pikseli w lewym górnym rogu.
Bakłażan Jeff
46
Zauważ, że ta odpowiedź zależy od jQueryUI, a nie tylko od jQuery. Może wyjaśnić, dlaczego to nie działa dla kilku z was.
btubbs
398

tl; dr: (spróbuj tutaj )

Jeśli masz następujący kod HTML:

<div id="menu" style="display: none;">
   <!-- menu stuff in here -->
   <ul><li>Menu item</li></ul>
</div>

<div class="parent">Hover over me to show the menu here</div>

możesz użyć następującego kodu JavaScript:

$(".parent").mouseover(function() {
    // .position() uses position relative to the offset parent, 
    var pos = $(this).position();

    // .outerWidth() takes into account border and padding.
    var width = $(this).outerWidth();

    //show the menu directly over the placeholder
    $("#menu").css({
        position: "absolute",
        top: pos.top + "px",
        left: (pos.left + width) + "px"
    }).show();
});

Ale to nie działa!

Działa to tak długo, jak menu i symbol zastępczy mają ten sam element nadrzędny przesunięcia. Jeśli nie, i nie masz zagnieżdżonych reguł CSS, które dbają o to, gdzie w DOM #menujest element, użyj:

$(this).append($("#menu"));

tuż przed linią pozycjonującą #menuelement.

Ale to wciąż nie działa!

Możesz mieć dziwny układ, który nie działa z tym podejściem. W takim przypadku wystarczy użyć wtyczki jQuery.ui (jak wspomniano w odpowiedzi poniżej), która obsługuje każdą możliwą sytuację . Pamiętaj, że będziesz musiał przejść show()do elementu menu przed wywołaniem position({...}); wtyczka nie może pozycjonować ukrytych elementów.

Aktualizuj uwagi 3 lata później w 2012 roku:

(Oryginalne rozwiązanie jest tutaj archiwizowane dla potomności)

Okazuje się więc, że oryginalna metoda, którą tu zastosowałem, była daleka od ideału. W szczególności upadłby, gdyby:

  • element nadrzędny przesunięcia menu nie jest elementem nadrzędnym elementu zastępczego elementu zastępczego
  • symbol zastępczy ma ramkę / wypełnienie

Na szczęście jQuery wprowadził metody ( position()i outerWidth()) już w 1.2.6, które znacznie ułatwiają znalezienie właściwych wartości w tym drugim przypadku. W pierwszym przypadku appendwstawienie elementu menu do symbolu zastępczego działa (ale złamie reguły CSS oparte na zagnieżdżaniu).

Jakub
źródło
168
Zaraz to dziwne: musiałem to zrobić innego dnia, nie mogłem sobie przypomnieć, jak go przeglądałem i dostałem ... tę odpowiedź! Kocham SOF.
Jacob
17
Heh - przydarzyło mi się to samo - nie pamiętam, jak coś zrobić, i znalazłem własną odpowiedź na temat Przepełnienia stosu.
Herb Caudill
16
Myślę, że twój styl div menu powinien używać display: none zamiast display: hidden.
Gabe
6
To nie zadziała poprawnie, gdy kontener menu ma pozycję: względną (lub cokolwiek poza dziedziczeniem), ponieważ pozycja: absolutne to wyłączy, a .offset wyłączy się w lewym górnym rogu strony.
Mike Cooper
3
W zależności od tego, w jaki sposób pozycjonowane jest twoje menu, .offset () jQuery może być użyty jako rozwijany zamiennik dla .position (). api.jquery.com/offset
Danny C
16

To w końcu działało dla mnie.

var showMenu = function(el, menu) {
    //get the position of the placeholder element  
    var pos = $(el).offset();    
    var eWidth = $(el).outerWidth();
    var mWidth = $(menu).outerWidth();
    var left = (pos.left + eWidth - mWidth) + "px";
    var top = 3+pos.top + "px";
    //show the menu directly over the placeholder  
    $(menu).css( { 
        position: 'absolute',
        zIndex: 5000,
        left: left, 
        top: top
    } );

    $(menu).hide().fadeIn();
};
Paweł
źródło
6

Oto napisana przeze mnie funkcja jQuery, która pomaga mi pozycjonować elementy.

Oto przykładowe użycie:

$(document).ready(function() {
  $('#el1').position('#el2', {
    anchor: ['br', 'tr'],
    offset: [-5, 5]
  });
});

Powyższy kod wyrównuje prawy dolny # el1 z prawym górnym # el2. ['cc', 'cc'] wyśrodkowuje # el1 w # el2. Upewnij się, że # el1 ma css pozycji: absolut i indeks Z: 10000 (lub jakąś naprawdę dużą liczbę), aby utrzymać go na szczycie.

Opcja przesunięcia pozwala przesuwać współrzędne o określoną liczbę pikseli.

Kod źródłowy jest poniżej:

jQuery.fn.getBox = function() {
  return {
    left: $(this).offset().left,
    top: $(this).offset().top,
    width: $(this).outerWidth(),
    height: $(this).outerHeight()
  };
}

jQuery.fn.position = function(target, options) {
  var anchorOffsets = {t: 0, l: 0, c: 0.5, b: 1, r: 1};
  var defaults = {
    anchor: ['tl', 'tl'],
    animate: false,
    offset: [0, 0]
  };
  options = $.extend(defaults, options);

  var targetBox = $(target).getBox();
  var sourceBox = $(this).getBox();

  //origin is at the top-left of the target element
  var left = targetBox.left;
  var top = targetBox.top;

  //alignment with respect to source
  top -= anchorOffsets[options.anchor[0].charAt(0)] * sourceBox.height;
  left -= anchorOffsets[options.anchor[0].charAt(1)] * sourceBox.width;

  //alignment with respect to target
  top += anchorOffsets[options.anchor[1].charAt(0)] * targetBox.height;
  left += anchorOffsets[options.anchor[1].charAt(1)] * targetBox.width;

  //add offset to final coordinates
  left += options.offset[0];
  top += options.offset[1];

  $(this).css({
    left: left + 'px',
    top: top + 'px'
  });

}
Venkat D.
źródło
3

Po co komplikować za dużo? Rozwiązanie jest bardzo proste

css:

.active-div{
position:relative;
}

.menu-div{
position:absolute;
top:0;
right:0;
display:none;
}

jquery:

$(function(){
    $(".active-div").hover(function(){
    $(".menu-div").prependTo(".active-div").show();
    },function(){$(".menu-div").hide();
})

Działa nawet jeśli

  • Dwa divy umieszczone gdziekolwiek indziej
  • Zmiana rozmiaru przeglądarki
gtamil
źródło
ta metoda nie działa, jeśli chcę emulować symbol zastępczy np. i pokazać go powyżej danych wejściowych (
tibalt 21.02.
To nie działa, gdy chcę wyrównać dwa elementy, które są rodzeństwem lub nawet całkowicie niezwiązane, co jest bardzo powszechne.
oriadam
3

Możesz użyć wtyczki jQuery PositionCalculator

Ta wtyczka zawiera również obsługę kolizji (odwracanie), dzięki czemu menu podobne do paska narzędzi można umieścić w widocznym miejscu.

$(".placeholder").on('mouseover', function() {
    var $menu = $("#menu").show();// result for hidden element would be incorrect
    var pos = $.PositionCalculator( {
        target: this,
        targetAt: "top right",
        item: $menu,
        itemAt: "top left",
        flip: "both"
    }).calculate();

    $menu.css({
        top: parseInt($menu.css('top')) + pos.moveBy.y + "px",
        left: parseInt($menu.css('left')) + pos.moveBy.x + "px"
    });
});

dla tego znacznika:

<ul class="popup" id="menu">
    <li>Menu item</li>
    <li>Menu item</li>
    <li>Menu item</li>
</ul>

<div class="placeholder">placeholder 1</div>
<div class="placeholder">placeholder 2</div>

Oto skrzypce: http://jsfiddle.net/QrrpB/1657/

TLindig
źródło
Konsola pisze: Niezdefiniowana nie jest funkcją dla linii: var pos = $ .PositionCalculator ({Czy możesz pomóc w rozwiązaniu problemu?
Alexandr Belov
@AlexandrBelov: Chyba nie załadowałeś wtyczki. Zanim będzie można go użyć, należy załadować plik js wtyczki PositionCalculator.
TLindig
2

Coś takiego?

$(menu).css("top", targetE1.y + "px"); 
$(menu).css("left", targetE1.x - widthOfMenu + "px");
slf
źródło
2

To działa dla mnie:

var posPersonTooltip = function(event) {
var tPosX = event.pageX - 5;
var tPosY = event.pageY + 10;
$('#personTooltipContainer').css({top: tPosY, left: tPosX});
devXen
źródło