Como posicionar um elemento em relação a outro com o jQuery?

354

Eu tenho um DIV oculto que contém um menu semelhante à barra de ferramentas.

Eu tenho um número de DIVs que estão habilitados para mostrar o menu DIV quando o mouse passa sobre eles.

Existe uma função interna que moverá o menu DIV para o canto superior direito do DIV ativo (mouse em movimento)? Estou procurando algo como$(menu).position("topright", targetEl);

Paulo
fonte
11
ter um olhar para stackoverflow.com/questions/8400876/... quais endereços de tantos problemas mais que pode ocorrer
Toskan
Consulte "As perguntas devem incluir" tags "em seus títulos?" , onde o consenso é "não, eles não deveriam"!
Andreas Niedermair
@ paul Sim, há uma pequena diferença no estilo. O título inicial desta pergunta foi prefixado com jQuery:, o que não é recomendado. Geralmente, devido à marcação adicional da pergunta, o que torna a prefixação inútil. Se a tecnologia for necessária no título, ela deverá ser capturada em uma frase real , não apenas em um prefixo - porque é para isso que servem as tags.
Andreas Niedermair

Respostas:

203

NOTA: Isso requer a interface do usuário do jQuery (não apenas o jQuery).

Agora você pode usar:

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

Para posicionamento rápido ( jQuery UI / Position ).

Você pode baixar a interface do usuário do jQuery aqui .

Uriel
fonte
11
Eu tenho tentado usar positon plugin, mas por alguma razão eu não posso obtê-lo para trabalho :(
Salman A
Também não funciona para mim. Tentar usar isso para posicionar uma div simples de cor sólida acima do corpo resultou em uma desconexão de 17 pixels na parte superior esquerda.
Eggplant Jeff
46
Observe que esta resposta depende do jQueryUI, não apenas do jQuery. Pode explicar por que não está funcionando para alguns de vocês.
btubbs
398

tl; dr: (experimente aqui )

Se você possui o seguinte 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>

então você pode usar o seguinte código 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();
});

Mas isso não funciona!

Isso funcionará desde que o menu e o espaço reservado tenham o mesmo pai de deslocamento. Se não, e você não possui regras CSS aninhadas que importam onde #menuestá o elemento DOM , use:

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

logo antes da linha que posiciona o #menuelemento.

Mas ainda não funciona!

Você pode ter um layout estranho que não funciona com essa abordagem. Nesse caso, basta usar o plug-in de posição do jQuery.ui (como mencionado na resposta abaixo), que lida com todas as eventualidades possíveis. Observe que você precisará show()do elemento de menu antes de chamar position({...}); o plug-in não pode posicionar elementos ocultos.

Notas da atualização 3 anos depois em 2012:

(A solução original está arquivada aqui para posteridade)

Então, o método original que eu tinha aqui estava longe de ser o ideal. Em particular, falharia se:

  • o pai de deslocamento do menu não é o pai de deslocamento do espaço reservado
  • o espaço reservado tem uma borda / preenchimento

Felizmente, o jQuery introduziu métodos ( position()e outerWidth()) na versão 1.2.6, que tornam muito mais fácil encontrar os valores corretos no último caso. No primeiro caso, a appendinserção do elemento de menu no espaço reservado funciona (mas quebrará as regras CSS com base no aninhamento).

Jacob
fonte
168
Uau, isso é esquisito: eu tive que fazer isso outro dia, não conseguia me lembrar de como, pesquisei no Google e obtive ... esta resposta! Tem que amar SOF.
Jacob
17
Heh - tive a mesma coisa comigo - não conseguia se lembrar de como fazer algo e encontrou minha própria resposta no Stack Overflow.
Herb Caudill
16
Eu acho que o seu estilo de menu div deve usar display: none em vez de display: hidden.
Gabe
6
Isso não funcionará corretamente quando o contêiner do menu tiver a posição: relativa (ou qualquer outra coisa além de herdar), pois a posição: absoluto desativará isso e .offset desativará a parte superior esquerda da página.
Mike Cooper
3
Dependendo de como o menu está posicionado, o .offset () do jQuery pode ser usado como um substituto para .position (). api.jquery.com/offset
Danny C #
16

Isto é o que funcionou para mim no final.

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();
};
Paulo
fonte
6

Aqui está uma função jQuery que escrevi que me ajuda a posicionar elementos.

Aqui está um exemplo de uso:

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

O código acima alinha o canto inferior direito de # el1 com o canto superior direito de # el2. ['cc', 'cc'] centralizaria # el1 em # el2. Certifique-se de que # el1 tenha o css de position: absolute e z-index: 10000 (ou algum número realmente grande) para mantê-lo no topo.

A opção de deslocamento permite que você desloque as coordenadas por um número especificado de pixels.

O código fonte está abaixo:

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.
fonte
3

Por que complicar demais? A solução é muito simples

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

Funciona mesmo se,

  • Duas divs colocadas em qualquer outro lugar
  • Redimensionado pelo navegador
gtamil
fonte
esse método não funciona se eu quiser emular um espaço reservado para ie, e mostrá-lo acima da entrada (
tibalt
Isso não funciona quando eu quero alinhar dois elementos que são irmãos ou mesmo completamente independentes, o que é muito comum.
oriadam 23/05
3

Você pode usar o plugin jQuery PositionCalculator

Esse plug-in também incluiu manipulação de colisão (flip), para que o menu semelhante à barra de ferramentas possa ser colocado em uma posição visível.

$(".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"
    });
});

para essa marcação:

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

Aqui está o violino: http://jsfiddle.net/QrrpB/1657/

TLindig
fonte
Console escreve Undefined não é uma função para a linha: var pos = $ .PositionCalculator ({Você pode por favor me ajude a resolver o problema?
Alexandr Belov
@AlexandrBelov: Eu acho que você não carregou o plugin. Antes de poder usá-lo, você deve carregar o arquivo js do plugin PositionCalculator.
TLindig
2

Algo assim?

$(menu).css("top", targetE1.y + "px"); 
$(menu).css("left", targetE1.x - widthOfMenu + "px");
slf
fonte
2

Isso funciona para mim:

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