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


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 .


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


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

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

}

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

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/


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

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});
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.