¿Cómo posicionar un elemento en relación con otro con jQuery?

354

Tengo un DIV oculto que contiene un menú similar a una barra de herramientas.

Tengo varios DIV que están habilitados para mostrar el menú DIV cuando el mouse se desplaza sobre ellos.

¿Existe una función incorporada que moverá el menú DIV a la parte superior derecha del DIV activo (desplazamiento del mouse)? Estoy buscando algo como$(menu).position("topright", targetEl);

Pablo
fuente
1
echar un vistazo a stackoverflow.com/questions/8400876/... qué direcciones tantos más problemas que puede ocurrir
Toskan
Consulte "¿Las preguntas deben incluir" etiquetas "en sus títulos?" , donde el consenso es "no, no deberían".
Andreas Niedermair
@paul Sí, hay una ligera diferencia en el estilo. El título inicial de esta pregunta tenía el prefijo jQuery: que no se recomienda. Por lo general, debido al etiquetado adicional de la pregunta, lo que hace que el prefijo sea inútil. Si se necesita la tecnología en el título, debe capturarse en una oración real , no solo un prefijo, porque para eso están las etiquetas.
Andreas Niedermair

Respuestas:

203

NOTA: Esto requiere jQuery UI (no solo jQuery).

Ahora puedes usar:

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

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

Puede descargar jQuery UI aquí .

Uriel
fuente
1
He estado tratando de usar el complemento positon, pero por alguna razón no puedo hacer que funcione :(
Salman A
Tampoco me funciona. Intentar usar esto para colocar un div de color sólido simple sobre el cuerpo resultó en que fuera 17 píxeles arriba a la izquierda.
Berenjena Jeff
46
Tenga en cuenta que esta respuesta depende de jQueryUI, no solo de jQuery. Podría explicar por qué no funciona para un par de ustedes.
btubbs
398

tl; dr: (pruébalo aquí )

Si tiene el siguiente 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>

entonces puede usar el siguiente 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();
});

¡Pero no funciona!

Esto funcionará siempre que el menú y el marcador de posición tengan el mismo desplazamiento principal. Si no lo hacen, y no tiene reglas CSS anidadas que se preocupan por el #menuelemento DOM , use:

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

justo antes de la línea que posiciona el #menuelemento.

¡Pero todavía no funciona!

Es posible que tenga un diseño extraño que no funciona con este enfoque. En ese caso, solo use el complemento de posición de jQuery.ui (como se menciona en una respuesta a continuación), que maneja cada eventualidad concebible. Tenga en cuenta que tendrá que ir show()al elemento del menú antes de llamar position({...}); El complemento no puede colocar elementos ocultos.

Notas de actualización 3 años después en 2012:

(La solución original se archiva aquí para la posteridad)

Entonces, resulta que el método original que tenía aquí estaba lejos de ser ideal. En particular, fallaría si:

  • el padre desplazado del menú no es el padre desplazado del marcador de posición
  • el marcador de posición tiene un borde / relleno

Afortunadamente, jQuery introdujo métodos ( position()y outerWidth()) en 1.2.6 que hacen que encontrar los valores correctos en este último caso sea mucho más fácil. Para el caso anterior, funciona appendel elemento de menú para el marcador de posición funciona (pero romperá las reglas CSS basadas en el anidamiento).

Jacob
fuente
168
Vaya, esto es extraño: tuve que hacer esto el otro día, no podía recordar cómo, busqué en Google y obtuve ... ¡esta respuesta! Tengo que amar a SOF.
Jacob
17
Heh, me ha pasado lo mismo, no podía recordar cómo hacer algo y encontré mi propia respuesta en Stack Overflow.
Herb Caudill
16
Creo que su estilo div de menú debería usar display: none en lugar de display: hidden.
Gabe
66
Esto no funcionará correctamente cuando el contenedor del menú tenga position: relative (o cualquier cosa además de heredar), ya que position: absolute eliminará eso y .offset desactivará en la esquina superior izquierda de la página.
Mike Cooper
3
Dependiendo de cómo esté posicionado su menú, jQuery's .offset () puede usarse como un reemplazo directo para .position (). api.jquery.com/offset
Danny C
16

Esto es lo que funcionó para mí al 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();
};
Pablo
fuente
6

Aquí hay una función jQuery que escribí que me ayuda a posicionar elementos.

Aquí hay un ejemplo de uso:

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

El código anterior alinea la esquina inferior derecha de # el1 con la esquina superior derecha de # el2. ['cc', 'cc'] centraría # el1 en # el2. Asegúrese de que # el1 tenga el css de posición: absoluto e índice z: 10000 (o algún número realmente grande) para mantenerlo en la parte superior.

La opción de desplazamiento le permite empujar las coordenadas por un número específico de píxeles.

El código fuente está abajo:

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

¿Por qué complicarse demasiado? La solución es muy simple.

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 incluso si,

  • Dos divs colocados en otro lugar
  • Navegador redimensionado
gtamil
fuente
este método no funciona si quiero emular un marcador de posición para, por ejemplo, y mostrarlo por encima de la entrada (
tibalt
Esto no funciona cuando quiero alinear dos elementos que son hermanos o incluso no están relacionados, lo cual es muy común.
oriadam
3

Puede usar el plugin jQuery PositionCalculator

Ese complemento también ha incluido el manejo de colisiones (flip), por lo que el menú tipo barra de herramientas se puede colocar en una posición visible.

$(".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 ese marcado:

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

Aquí está el violín: http://jsfiddle.net/QrrpB/1657/

TLindig
fuente
La consola escribe Undefined no es una función para la línea: var pos = $ .PositionCalculator ({¿Puede ayudar a resolver el problema?
Alexandr Belov
@AlexandrBelov: Supongo que no cargó el complemento. Antes de poder usarlo, debe cargar el archivo js del plugin PositionCalculator.
TLindig
2

¿Algo como esto?

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

Esto funciona para mi:

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