วิธีการวางองค์ประกอบหนึ่งที่เกี่ยวข้องกับอีกด้วย jQuery?


354

ฉันมี DIV ที่ซ่อนอยู่ซึ่งมีเมนูเหมือนแถบเครื่องมือ

ฉันมี DIV จำนวนหนึ่งซึ่งเปิดใช้งานเพื่อแสดงเมนู DIV เมื่อเมาส์อยู่เหนือพวกเขา

มีฟังก์ชั่นในตัวซึ่งจะย้ายเมนู DIV ไปทางขวาบนของ DIV ที่ใช้งานอยู่ (โฮเวอร์เมาส์) DIV หรือไม่ ฉันกำลังมองหาบางอย่างเช่น$(menu).position("topright", targetEl);


1
ลองดูที่stackoverflow.com/questions/8400876/…ซึ่งจัดการปัญหาอื่น ๆ อีกมากมายที่สามารถเกิดขึ้นได้
Toskan

โปรดดู"คำถามควรมี" แท็ก "ในชื่อเรื่องหรือไม่" ที่ฉันทามติคือ "ไม่พวกเขาไม่ควร"!
Andreas Niedermair

@ พอลมีสไตล์แตกต่างกันเล็กน้อย ชื่อเริ่มต้นของคำถามนี้นำหน้าด้วยjQuery:ซึ่งไม่ได้รับการสนับสนุน โดยปกติแล้วเนื่องจากการติดแท็กคำถามเพิ่มเติมซึ่งทำให้คำนำหน้าไม่มีประโยชน์ หากจำเป็นต้องใช้เทคโนโลยีในชื่อเรื่องมันควรจะถูกจับในประโยคจริงไม่ใช่แค่คำนำหน้า - เพราะนั่นคือแท็กที่มีไว้สำหรับ
Andreas Niedermair

คำตอบ:


203

หมายเหตุ:สิ่งนี้ต้องการ jQuery UI (ไม่ใช่แค่ 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 พิกเซลไปทางซ้ายบน
มะเขือม่วง Jeff

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 ที่ซ้อนกันซึ่งดูแลว่า#menuองค์ประกอบอยู่ใน DOM ใดให้ใช้:

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

ก่อนหน้าบรรทัดที่วางตำแหน่ง#menuองค์ประกอบ

แต่มันก็ยังใช้งานไม่ได้!

คุณอาจมีเลย์เอาต์แปลก ๆ ที่ไม่สามารถใช้กับวิธีนี้ได้ ในกรณีนี้ให้ใช้ปลั๊กอินตำแหน่งของ jQuery.ui (ดังที่ได้กล่าวไว้ในคำตอบด้านล่าง) ซึ่งจัดการเหตุการณ์ที่เป็นไปได้ทุกอย่าง โปรดทราบว่าคุณจะต้องshow()องค์ประกอบเมนูก่อนที่จะโทรposition({...}); ปลั๊กอินไม่สามารถวางตำแหน่งองค์ประกอบที่ซ่อนอยู่

อัพเดทบันทึก 3 ปีต่อมาในปี 2012:

(โซลูชันดั้งเดิมถูกเก็บถาวรที่นี่เพื่อลูกหลาน)

ดังนั้นกลับกลายเป็นว่าวิธีดั้งเดิมที่ฉันมีที่นี่นั้นยังห่างไกลจากอุดมคติ โดยเฉพาะอย่างยิ่งมันจะล้มเหลวหาก:

  • parent offset ของเมนูไม่ใช่ parent offset ของตัวแทน
  • ตัวยึดตำแหน่งมีเส้นขอบ / ช่องว่างภายใน

โชคดีที่ jQuery ได้แนะนำวิธีการ ( position()และouterWidth()) ย้อนกลับไปใน 1.2.6 ที่ทำให้การค้นหาค่าที่ถูกต้องในกรณีหลังนี้ง่ายขึ้นมาก สำหรับกรณีก่อนหน้านี้appendการใช้อิลิเมนต์เมนูกับตัวยึดตำแหน่ง (แต่จะทำลายกฎ CSS ตามการซ้อน)


168
โอ้โหนี่มันนอกลู่นอกทาง: ฉันต้องทำสิ่งนี้ในวันอื่นจำไม่ได้แล้วว่าทำยังไงและได้ ... คำตอบนี้! ต้องรัก SOF
344209 Jacob

17
Heh - ฉันมีสิ่งเดียวกันเกิดขึ้นกับฉัน - จำไม่ได้ว่าจะทำอะไรและพบคำตอบของฉันใน Stack Overflow
สมุนไพร Caudill

16
ฉันคิดว่าเมนู div ของคุณควรใช้ display: none แทน display: hidden
Gabe

6
สิ่งนี้จะไม่ทำงานอย่างถูกต้องเมื่อคอนเทนเนอร์ของเมนูมีตำแหน่ง: สัมพัทธ์ (หรืออะไรก็ตามที่นอกเหนือจากการสืบทอด) เนื่องจากตำแหน่ง: สัมบูรณ์จะกดปุ่มนั้นและ. offset จะปิดที่ด้านบนซ้ายของหน้า
Mike Cooper

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: absolute และ z-index: 10,000 (หรือบางจำนวนมากจริงๆ) เพื่อให้อยู่ด้านบน

ตัวเลือกออฟเซตอนุญาตให้คุณเลื่อนตำแหน่งพิกัดตามจำนวนพิกเซลที่ระบุ

ซอร์สโค้ดอยู่ด้านล่าง:

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

มันทำงานได้แม้ว่า

  • div สองอันวางไว้ที่อื่น
  • เบราว์เซอร์ปรับขนาดใหม่

วิธีนี้ใช้ไม่ได้หากฉันต้องการเลียนแบบตัวยึดตำแหน่งและแสดงไว้เหนืออินพุต (
tibalt

สิ่งนี้ไม่ทำงานเมื่อฉันต้องการจัดองค์ประกอบสองอย่างที่เป็นพี่น้องหรือแม้กระทั่งไม่เกี่ยวข้องกันอย่างสมบูรณ์ซึ่งเป็นเรื่องปกติมาก
oriadam

3

คุณสามารถใช้ jQuery plugin 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/


คอนโซลเขียน Undefined ไม่ใช่ฟังก์ชันสำหรับบรรทัด: var pos = $ .PositionCalculator ({คุณช่วยกรุณาแก้ปัญหาได้มั้

@AlexandrBelov: ฉันเดาว่าคุณไม่ได้โหลดปลั๊กอิน ก่อนที่คุณจะสามารถใช้งานได้คุณต้องโหลดไฟล์ js ของปลั๊กอิน PositionCalculator ก่อน
TLindig


2

สิ่งนี้ใช้ได้กับฉัน:

var posPersonTooltip = function(event) {
var tPosX = event.pageX - 5;
var tPosY = event.pageY + 10;
$('#personTooltipContainer').css({top: tPosY, left: tPosX});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.