การตรวจจับเมื่อความสูงของ div เปลี่ยนแปลงโดยใช้ jQuery


141

ฉันได้ div ที่มีเนื้อหาบางส่วนที่ถูกเพิ่มและลบแบบไดนามิกดังนั้นความสูงของมันจึงเปลี่ยนแปลงบ่อย ฉันยังมี div ที่อยู่ในตำแหน่งโดยตรงภายใต้ javascript ดังนั้นหากฉันไม่สามารถตรวจพบเมื่อความสูงของการเปลี่ยนแปลง div ฉันไม่สามารถปรับตำแหน่ง div ด้านล่างได้

ดังนั้นฉันจะตรวจจับได้อย่างไรเมื่อความสูงของ div นั้นเปลี่ยนแปลง? ฉันคิดว่ามีกิจกรรม jQuery บางอย่างที่ฉันต้องใช้ แต่ฉันไม่แน่ใจ


4
ฉันสงสัยว่าทำไมไม่ต้องการใช้ปลั๊กอินเมื่อใช้ jQuery
Andre Calil

1
@ user007 อะไรทำให้ขนาดองค์ประกอบของคุณเปลี่ยนไป?
A. Wolff

@ ทำให้ความสูง div ของฉันเปลี่ยนไปเมื่อบางรายการต่อท้ายมันจะทำการผนวกโดย jquery
user007

1
@ user007 ดังนั้นเมื่อคุณต่อท้ายสิ่งที่ DIV คุณสามารถทริกเกอร์เหตุการณ์การปรับขนาดแบบกำหนดเองสำหรับ DIV อีกวิธีหนึ่ง (IMO ที่แย่ที่สุด) สามารถใช้วิธีการแบบกำหนดเองสำหรับการต่อท้ายเนื้อหาซึ่งขยายวิธีการต่อท้าย jquery ดั้งเดิม () ใช้กับการติดต่อกลับเช่น
A. Wolff

@roasted ขอบคุณสำหรับเคล็ดลับ
user007

คำตอบ:


64

ใช้เซ็นเซอร์ปรับขนาดจากไลบรารี css-element-query:

https://github.com/marcj/css-element-queries

new ResizeSensor(jQuery('#myElement'), function() {
    console.log('myelement has been resized');
});

มันใช้วิธีการตามเหตุการณ์และไม่เสียเวลาซีพียูของคุณ ใช้ได้กับทุกเบราว์เซอร์ IE7 +


5
วิธีแก้ปัญหาที่ดีคือใช้องค์ประกอบใหม่ที่มองไม่เห็นเป็นภาพซ้อนทับบนเป้าหมายที่ต้องการและใช้เหตุการณ์ "เลื่อน" บนภาพซ้อนทับเพื่อกระตุ้นการเปลี่ยนแปลง
Eike Thies

2
นี่เป็นทางออกเดียวที่ใช้งานได้ในทุกกรณีรวมถึงเมื่อเนื้อหาและแอตทริบิวต์ไม่เปลี่ยนแปลง แต่การเปลี่ยนแปลงส่วนข้อมูล (ตัวอย่าง: เปอร์เซ็นต์การใช้ css)
FF_Dev

2
ทางออกที่ดีที่สุด
dlsso

1
นี่ไม่ใช่คำตอบที่ได้รับคะแนนสูงสุดนี่เป็นโศกนาฏกรรม ใช้งานได้จริง 100%
Jimbo Jonny

ดูเหมือนจะไม่ทำงานสำหรับองค์ประกอบที่เริ่มปิดซ่อน
greatwitenorth

48

ฉันเขียนปลั๊กอินบางครั้งสำหรับผู้ฟังattrchangeซึ่งโดยทั่วไปจะเพิ่มฟังฟังก์ชั่นการเปลี่ยนคุณสมบัติ แม้ว่าฉันจะบอกว่ามันเป็นปลั๊กอินจริงๆแล้วมันเป็นฟังก์ชั่นที่เรียบง่ายที่เขียนเป็นปลั๊กอิน jQuery .. ดังนั้นหากคุณต้องการ .. ถอดแถบโค้ด specfic ของปลั๊กอินออกและใช้ฟังก์ชั่นหลัก

หมายเหตุ: รหัสนี้ไม่ได้ใช้การสำรวจความคิดเห็น

ตรวจสอบตัวอย่างง่าย ๆ นี้http://jsfiddle.net/aD49d/

$(function () {
    var prevHeight = $('#test').height();
    $('#test').attrchange({
        callback: function (e) {
            var curHeight = $(this).height();            
            if (prevHeight !== curHeight) {
               $('#logger').text('height changed from ' + prevHeight + ' to ' + curHeight);

                prevHeight = curHeight;
            }            
        }
    }).resizable();
});

หน้าปลั๊กอิน: http://meetselva.github.io/attrchange/

เวอร์ชันย่อ: (1.68kb)

(function(e){function t(){var e=document.createElement("p");var t=false;if(e.addEventListener)e.addEventListener("DOMAttrModified",function(){t=true},false);else if(e.attachEvent)e.attachEvent("onDOMAttrModified",function(){t=true});else return false;e.setAttribute("id","target");return t}function n(t,n){if(t){var r=this.data("attr-old-value");if(n.attributeName.indexOf("style")>=0){if(!r["style"])r["style"]={};var i=n.attributeName.split(".");n.attributeName=i[0];n.oldValue=r["style"][i[1]];n.newValue=i[1]+":"+this.prop("style")[e.camelCase(i[1])];r["style"][i[1]]=n.newValue}else{n.oldValue=r[n.attributeName];n.newValue=this.attr(n.attributeName);r[n.attributeName]=n.newValue}this.data("attr-old-value",r)}}var r=window.MutationObserver||window.WebKitMutationObserver;e.fn.attrchange=function(i){var s={trackValues:false,callback:e.noop};if(typeof i==="function"){s.callback=i}else{e.extend(s,i)}if(s.trackValues){e(this).each(function(t,n){var r={};for(var i,t=0,s=n.attributes,o=s.length;t<o;t++){i=s.item(t);r[i.nodeName]=i.value}e(this).data("attr-old-value",r)})}if(r){var o={subtree:false,attributes:true,attributeOldValue:s.trackValues};var u=new r(function(t){t.forEach(function(t){var n=t.target;if(s.trackValues){t.newValue=e(n).attr(t.attributeName)}s.callback.call(n,t)})});return this.each(function(){u.observe(this,o)})}else if(t()){return this.on("DOMAttrModified",function(e){if(e.originalEvent)e=e.originalEvent;e.attributeName=e.attrName;e.oldValue=e.prevValue;s.callback.call(this,e)})}else if("onpropertychange"in document.body){return this.on("propertychange",function(t){t.attributeName=window.event.propertyName;n.call(e(this),s.trackValues,t);s.callback.call(this,t)})}return this}})(jQuery)

25
วิธีนี้จะช่วยแก้ปัญหาได้หากคุณปรับขนาด div ด้วยตัวเองสิ่งนี้ไม่สามารถแก้คำถามเดิมได้หรือไม่ หากคุณเพิ่มเนื้อหาแบบไดนามิกจะไม่ตรวจพบการเปลี่ยนแปลงความสูง: jsfiddle.net/aD49d/25
smets.kevin

ฉันก็จะสนใจที่จะรู้ว่าหากมีวิธีที่จะทำให้งานนี้สำหรับเนื้อหาแบบไดนามิก
EricP

4
@JoeCoder รหัส attrchange นี้ขึ้นอยู่กับเหตุการณ์ DOM ที่ถูกเรียกโดยเบราว์เซอร์เมื่อมีการกระทำของผู้ใช้ อย่างไรก็ตามเนื้อหาแบบไดนามิกในตัวอย่างนั้นถูกรวมไว้ในทางโปรแกรมซึ่งน่าเสียดายที่ไม่ทำให้เกิดเหตุการณ์ใด ๆ "การสำรวจ" ดูเหมือนจะเป็นอีกตัวเลือกที่ง่ายกว่าที่นี่ .. ตัวเลือกอื่นจะสามารถทริกเกอร์ด้วยตนเองได้หลังจากรวมเนื้อหาแบบไดนามิกแล้ว
Selvakumar Arumugam

28

คุณสามารถใช้เหตุการณ์ DOMSubtreeModified

$(something).bind('DOMSubtreeModified' ...

แต่สิ่งนี้จะเกิดขึ้นแม้ว่าขนาดจะไม่เปลี่ยนแปลงและการกำหนดตำแหน่งใหม่เมื่อใดก็ตามที่การยิงสามารถทำให้เกิดการปะทะได้ จากประสบการณ์ของฉันโดยใช้วิธีนี้การตรวจสอบว่ามิติที่มีการเปลี่ยนแปลงมีราคาไม่แพงหรือไม่และคุณอาจพิจารณารวมทั้งสองอย่างเข้าด้วยกัน

หรือถ้าคุณกำลังแก้ไข div โดยตรง (แทนที่จะ div ถูกเปลี่ยนแปลงโดยอินพุตของผู้ใช้ในรูปแบบที่ไม่สามารถคาดเดาได้เช่นถ้าเป็น contentEditable) คุณสามารถเริ่มเหตุการณ์ที่กำหนดเองได้ทุกเมื่อที่คุณทำเช่นนั้น

ข้อเสีย: IE และ Opera ไม่ได้ใช้เหตุการณ์นี้


12
IE & Opera ไม่ได้ใช้กิจกรรมนี้: quirksmode.org/dom/events/index.html
DEfusion

14
DomSubtreeModified ได้ depricated
Adonis K. Kakoulidis

2
วิธีที่ทันสมัยในการทำเช่นนี้คือใช้ MutationObserver: developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Christian Bankester

21

นี่คือวิธีที่ฉันจัดการกับปัญหานี้เมื่อเร็ว ๆ นี้:

$('#your-resizing-div').bind('getheight', function() {
    $('#your-resizing-div').height();
});

function your_function_to_load_content() {
    /*whatever your thing does*/
    $('#your-resizing-div').trigger('getheight');
}

ฉันรู้ว่าฉันไปปาร์ตี้ไม่กี่ปีก็แค่คิดว่าคำตอบของฉันอาจช่วยคนบางคนในอนาคตโดยไม่ต้องดาวน์โหลดปลั๊กอินใด ๆ


1
ฉันเดาในบางวิธีนี่ไม่ใช่วิธีที่ดีที่สุดที่จะทำ แต่จริงๆแล้วฉันชอบมันมากเพราะมันหมายความว่าคุณสามารถเรียกมันว่าเป็นการโทรกลับในตอนท้ายของอนิเมชั่น ปลั๊กอินปรับขนาดจะทำการยิงตลอดทั้งภาพเคลื่อนไหวซึ่งอาจเป็นประโยชน์ แต่อาจทำให้เกิดปัญหาได้เช่นกัน อย่างน้อยวิธีนี้ช่วยให้คุณควบคุมเวลาที่จะเริ่มการตรวจสอบความสูง
andyface

รหัสของคุณทำอะไร? เหตุใดเราจึงไม่สามารถใช้รหัสที่คุณเขียนไว้ในเหตุการณ์ผูกในฟังก์ชันที่มีการผูกและการทริกเกอร์
user1447420

แต่นี่ไม่ใช่อัตโนมัติใช่ไหม
อัลเบิร์ตคาตาลัน

17

คุณสามารถใช้MutationObserverคลาส

MutationObserverให้นักพัฒนามีวิธีตอบสนองต่อการเปลี่ยนแปลงใน DOM มันถูกออกแบบมาแทนเหตุการณ์การกลายพันธุ์ที่กำหนดไว้ในข้อมูลจำเพาะเหตุการณ์ DOM3

ตัวอย่าง ( แหล่งที่มา )

// select the target node
var target = document.querySelector('#some-id');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  });    
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();

นี่คือคำตอบที่ถูกต้อง ลองดูที่ MutationS บทสรุปห้องสมุดที่สร้างบน MutationObservers: github.com/rafaelw/mutation-summary
Christian Bankester

9

มีปลั๊กอิน jQuery ที่สามารถจัดการกับสิ่งนี้ได้เป็นอย่างดี

http://www.jqui.net/jquery-projects/jquery-mutate-official/

นี่คือตัวอย่างของสถานการณ์ที่แตกต่างกันไปเมื่อความสูงเปลี่ยนไปหากคุณปรับขนาด div ที่มีขอบสีแดง

http://www.jqui.net/demo/mutate/


มันสวยงาม แต่โดยค่าเริ่มต้นจะทำการสำรวจความคิดเห็น UI ทุกมิลลิวินาทีสำหรับการเปลี่ยนแปลงหรือไม่ มันมีประสิทธิภาพไหม?
Michael Scott Cuthbert

1
@MichaelScottCuthbert มันถูกเขียนมานานแล้ว แต่ฉันใช้setTimeoutดังนั้นมันจะเป็น 1ms + [เวลาที่ใช้ในการตรวจสอบ] ในระยะสั้น แต่ความคิดคือการฟังอย่างต่อเนื่องเมื่อคุณทำเช่นนั้นอีกครั้งมันก็เหมือน คิว. ฉันแน่ใจว่าฉันสามารถทำได้ดีกว่า แต่ไม่มากนัก
Val

อ่าใช่ฉันเห็นว่าคุณประมาณหนึ่งปีก่อนที่จะแก้ปัญหาของเวก้า (ซึ่งฉันใช้ในที่สุด) และก่อนหน้า DOMSubtreeModified ฯลฯ ผู้ฟังได้รับการสนับสนุนอย่างกว้างขวาง ฉันเรียนรู้อะไรมากมายจากการอ่านโค้ดของคุณดังนั้นฉันคิดว่ามันคุ้มค่าที่จะต้องรักษาลิงก์ไว้
Michael Scott Cuthbert

7

เพื่อตอบสนองต่อ user007:

หากความสูงขององค์ประกอบของคุณมีการเปลี่ยนแปลงเนื่องจากรายการจะถูกผนวกเข้ากับการใช้ .append()คุณไม่จำเป็นต้องตรวจสอบการเปลี่ยนแปลงความสูง เพียงเพิ่มตำแหน่งขององค์ประกอบที่สองของคุณในฟังก์ชั่นเดียวกับที่คุณเพิ่มเนื้อหาใหม่ในองค์ประกอบแรกของคุณ

ในขณะที่:

ตัวอย่างการทำงาน

$('.class1').click(function () {
    $('.class1').append("<div class='newClass'><h1>This is some content</h1></div>");
    $('.class2').css('top', $('.class1').offset().top + $('.class1').outerHeight());
});

2

คุณสามารถสร้าง setInterval อย่างง่าย

function someJsClass()
{
  var _resizeInterval = null;
  var _lastHeight = 0;
  var _lastWidth = 0;
  
  this.Initialize = function(){
    var _resizeInterval = setInterval(_resizeIntervalTick, 200);
  };
  
  this.Stop = function(){
    if(_resizeInterval != null)
      clearInterval(_resizeInterval);
  };
  
  var _resizeIntervalTick = function () {
    if ($(yourDiv).width() != _lastWidth || $(yourDiv).height() != _lastHeight) {
      _lastWidth = $(contentBox).width();
      _lastHeight = $(contentBox).height();
      DoWhatYouWantWhenTheSizeChange();
    }
  };
}

var class = new someJsClass();
class.Initialize();

แก้ไข:

นี่คือตัวอย่างของคลาส แต่คุณสามารถทำสิ่งที่ง่ายที่สุด


0

คุณสามารถใช้สิ่งนี้ได้ แต่รองรับเฉพาะ Firefox และ Chrome

$(element).bind('DOMSubtreeModified', function () {
  var $this = this;
  var updateHeight = function () {
    var Height = $($this).height();
    console.log(Height);
  };
  setTimeout(updateHeight, 2000);
});


0

ค่อนข้างธรรมดา แต่ใช้งานได้:

function dynamicHeight() {
    var height = jQuery('').height();
    jQuery('.edito-wrapper').css('height', editoHeight);
}
editoHeightSize();

jQuery(window).resize(function () {
    editoHeightSize();
});

สิ่งนี้จะถูกไล่ออกเมื่อมีการปรับขนาดหน้าต่าง แต่ OP ต้องการผูกเหตุการณ์การปรับขนาดกับคอนเทนเนอร์เฉพาะ
Fanie Void
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.