Как позиционировать один элемент относительно другого с помощью jQuery?

354

У меня есть скрытый DIV, который содержит меню, похожее на панель инструментов.

У меня есть несколько DIV, которые позволяют отображать меню DIV при наведении на них курсора мыши.

Есть ли встроенная функция, которая будет перемещать меню DIV в верхнем правом углу активной (наведение мыши) DIV? Я ищу что-то вроде$(menu).position("topright", targetEl);

Павел
источник
1
взгляните на stackoverflow.com/questions/8400876/…, который решает гораздо больше проблем, которые могут возникнуть
Toskan
Пожалуйста, смотрите "Должны ли вопросы включать" теги "в заголовки?" где консенсус "нет, они не должны"!
Андреас Нидермайр
@ Пол Да, есть небольшая разница в стиле. Первоначальный заголовок этого вопроса был с префиксом jQuery:, что не приветствуется. Обычно из-за дополнительной пометки вопроса, что делает префикс бесполезным. Если в заголовке нужна технология , она должна быть записана в реальном предложении, а не просто в префиксе, потому что для этого нужны теги.
Андреас Нидермайр

Ответы:

203

ПРИМЕЧАНИЕ. Для этого требуется пользовательский интерфейс jQuery (а не только jQuery).

Теперь вы можете использовать:

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

Для быстрого позиционирования ( jQuery UI / Position ).

Вы можете скачать jQuery UI здесь .

Уриэль
источник
1
Я пытался использовать Positon плагин, но по какой-то причине я просто не могу заставить его работать :(
Salman A
Также не работает для меня. Попытка использовать это, чтобы поместить простой однотонный div над телом, привела к тому, что он был отключен на 17 пикселей вверху слева.
Баклажан Джефф
46
Обратите внимание, что этот ответ зависит от jQueryUI, а не только от jQuery. Могу объяснить, почему это не работает на пару из вас.
Bubbs
398

tl; dr: (попробуйте здесь )

Если у вас есть следующий 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>

тогда вы можете использовать следующий код 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();
});

Но это не работает!

Это будет работать до тех пор, пока у меню и заполнителя будет один и тот же родительский элемент смещения. Если нет, и у вас нет вложенных правил CSS, которые заботятся о том, где находится #menuэлемент DOM , используйте:

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

прямо перед строкой, которая позиционирует #menuэлемент.

Но это все еще не работает!

У вас может быть странный макет, который не работает с этим подходом. В этом случае просто используйте плагин позиции jQuery.ui (как упомянуто в ответе ниже), который обрабатывает все возможные варианты. Обратите внимание, что вам придется до show()элемента меню перед вызовом position({...}); плагин не может позиционировать скрытые элементы.

Обновление заметки через 3 года в 2012 году:

(Оригинальное решение заархивировано здесь для потомков)

Итак, получается, что оригинальный метод, который я здесь использовал, был далек от идеала. В частности, он потерпит неудачу, если:

  • родительский элемент смещения меню не является родителем смещения заполнителя
  • заполнитель имеет границы / отступы

К счастью, в 1.2.6 jQuery представил методы ( position()и outerWidth()), которые значительно упрощают поиск правильных значений в последнем случае. В первом случае appendиспользование элемента меню в качестве заполнителя работает (но нарушает правила CSS, основанные на вложенности).

Иаков
источник
168
Вау, это странно: я должен был сделать это на днях, не мог вспомнить, как, погуглил и получил ... этот ответ! Должен любить SOF.
Джейкоб
17
Хех - у меня было то же самое, что случилось со мной - я не мог вспомнить, как что-то сделать, и нашел свой ответ на Stack Overflow.
Herb Caudill
16
Я думаю, что ваш стиль div меню должен использовать display: none вместо display: hidden.
Гейб
6
Это не будет работать должным образом, когда контейнер меню имеет позицию: относительный (или что-то кроме наследования), так как положение: абсолютное отключит это, а .offset отключит верхний левый угол страницы.
Майк Купер
3
В зависимости от того, как расположено ваше меню, jQuery .offset () может быть использован в качестве замены для .position (). api.jquery.com/offset
Дэнни С
16

Это то, что сработало для меня в конце.

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

Вот функция jQuery, которую я написал, которая помогает мне позиционировать элементы.

Вот пример использования:

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

Код выше выравнивает правый нижний угол # el1 с правым верхним краем # el2. ['cc', 'cc'] будет центрировать # el1 в # el2. Убедитесь, что у # el1 есть css of position: absolute и z-index: 10000 (или какое-то действительно большое число), чтобы держать его на вершине.

Опция смещения позволяет перемещать координаты на указанное количество пикселей.

Исходный код ниже:

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

Зачем усложнять слишком много? Решение очень простое

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

Это работает, даже если,

  • Два дивы размещены в другом месте
  • Браузер изменен
gtamil
источник
этот метод не работает, если я хочу эмулировать заполнитель для ie и показать его выше ввода (
tibalt
Это не работает, когда я хочу выровнять два элемента, которые являются родными или даже совершенно не связанными, что очень часто встречается.
Ориадам
3

Вы можете использовать плагин jQuery PositionCalculator

Этот плагин также включает в себя обработку столкновений (переворачивание), поэтому меню, похожее на панель инструментов, может быть размещено в видимом месте.

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

для этой разметки:

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

Вот скрипка: http://jsfiddle.net/QrrpB/1657/

TLindig
источник
Запись в консоли Undefined не является функцией для строки: var pos = $ .PositionCalculator ({Не могли бы вы помочь решить проблему?
Александр Белов
@AlexandrBelov: Я полагаю, вы не загрузили плагин. Прежде чем вы сможете его использовать, вы должны загрузить js-файл плагина PositionCalculator.
TLindig
2

Что-то вроде этого?

$(menu).css("top", targetE1.y + "px"); 
$(menu).css("left", targetE1.x - widthOfMenu + "px");
SLF
источник
2

Это работает для меня:

var posPersonTooltip = function(event) {
var tPosX = event.pageX - 5;
var tPosY = event.pageY + 10;
$('#personTooltipContainer').css({top: tPosY, left: tPosX});
devXen
источник