Як розташувати один елемент відносно іншого за допомогою jQuery?


354

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

У мене є декілька DIV, які дозволяють показувати меню DIV, коли миша на них клацає.

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


1
подивіться на stackoverflow.com/questions/8400876/…, де вирішується ще стільки проблем, які можуть виникнути
Тоскан

Будь ласка, дивіться "Чи повинні питання включати" теги "у своїх заголовках?" , де консенсус "ні, вони не повинні"!
Андреас Нідермайр

@paul Так, в стилі є незначна різниця. Початкова назва цього питання була префіксованою jQuery:, що не рекомендується. Зазвичай через додаткове тегування питання, що робить префіксацію марною. Якщо в заголовку потрібна технологія , її слід відображати в реальному реченні, а не просто в префіксі - адже саме для цього використовуються теги.
Андреас Нідермайр

Відповіді:


203

ПРИМІТКА: цього потрібен інтерфейс jQuery (не лише jQuery).

Тепер ви можете використовувати:

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

Для швидкого позиціонування ( jQuery UI / Position) ).

Ви можете завантажити інтерфейс jQuery тут .


1
Я намагався використовувати плагін positon, але чомусь я просто не можу змусити його працювати :(
Salman A

Також для мене не працює. Спроба використати це для розташування простого дивного кольорового кольору над тілом, це призвело до його відключення на 17 пікселів у верхньому лівому куті.
Баклажан Джефф

46
Зауважте, що ця відповідь залежить від jQueryUI, а не тільки jQuery. Можна пояснити, чому це не працює для вас двох.
btubbs

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, які цікавлять, де в DOM #menuелемент, скористайтеся:

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

безпосередньо перед рядком, який позиціонує #menuелемент.

Але це все ще не працює!

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

Оновлення приміток через 3 роки у 2012 році:

(Оригінальне рішення архівується тут для нащадків)

Отже, виходить, що оригінальний метод, який я тут мав, був далеко не ідеальним. Зокрема, це буде невдалим, якщо:

  • батьківський зсув меню не є батьком зсуву заповнювача
  • у заповнювача є бордюр / прокладка

На щастя, jQuery представив методи ( position()та outerWidth()) ще в 1.2.6, які значно полегшують пошук правильних значень в останньому випадку. У першому випадку appendпрацює елемент меню на заповнювачі (але порушує правила CSS на основі введення).


168
Ось це вигадливо: мені довелося це робити днями, не можу згадати, як, гуглили це і отримали ... цю відповідь! Треба любити SOF.
Яків

17
Гей - у мене було те саме, що трапилося зі мною - я не міг пригадати, як щось робити, і знайшов власну відповідь на Stack Overflow.
Herb Caudill

16
Я думаю, що у вашому стилі діва меню слід використовувати display: none замість display: hidden.
Гейб

6
Це не спрацює належним чином, коли контейнер меню має позицію: відносне (або що-небудь крім спадкового), оскільки позиція: абсолютне відключить це, а. Offset відключить у верхньому лівому куті сторінки.
Майк Купер

3
Залежно від того, як розміщено ваше меню .offset () jQuery може використовуватися як замена для .position (). api.jquery.com/offset
Danny C

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 позиції: абсолютний та z-індекс: 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();
})

Це працює, навіть якщо

  • Два діви розміщені деінде
  • Переглядач розміру

цей метод не працює, якщо я хочу імітувати заповнювач, тобто відображати його над входом (
tibalt,

Це не спрацьовує, коли я хочу вирівняти два елементи, які є побратимами або навіть зовсім не пов'язані між собою, що дуже часто.
oriadam

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/


Console пише Undefined не є функцією для рядка: var pos = $ .PositionCalculator ({Чи можете ви допомогти вирішити проблему?
Олександр Белов

@AlexandrBelov: Я думаю, ви не завантажили плагін. Перш ніж ви зможете ним скористатися, вам потрібно завантажити js-файл плагіна PositionCalculator.
TLindig

2

Щось на зразок цього?

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

2

Це працює для мене:

var posPersonTooltip = function(event) {
var tPosX = event.pageX - 5;
var tPosY = event.pageY + 10;
$('#personTooltipContainer').css({top: tPosY, left: tPosX});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.