Mendeteksi ketika ketinggian div berubah menggunakan jQuery

141

Saya punya div yang berisi beberapa konten yang ditambahkan dan dihapus secara dinamis, jadi tingginya sering berubah. Saya juga memiliki div yang benar-benar diposisikan tepat di bawahnya dengan javascript, jadi kecuali saya dapat mendeteksi ketika ketinggian div berubah, saya tidak dapat memposisikan div di bawahnya.

Jadi, bagaimana saya bisa mendeteksi ketika ketinggian div itu berubah? Saya berasumsi ada beberapa acara jQuery yang perlu saya gunakan, tapi saya tidak yakin yang mana yang harus dihubungkan.

Bob Somers
sumber
4
Saya ingin tahu mengapa orang tidak ingin menggunakan plugin saat menggunakan jQuery.
Andre Calil
1
@ user007 Apa yang membuat ukuran elemen Anda berubah?
A. Wolff
@mengeringkan perubahan ketinggian div saya ketika beberapa item ditambahkan ke dalamnya, tambahkan dilakukan oleh jquery
user007
1
@ user007 jadi ketika Anda menambahkan sesuatu ke DIV, Anda dapat memicu acara ubah ukuran khusus untuk DIV. Cara lain (IMO terburuk) dapat menggunakan metode khusus untuk menambahkan konten yang hanya memperpanjang metode jquery append () asli, menggunakannya dengan callback misalnya
A. Wolff
@Rasted Terima kasih atas tipnya.
user007

Jawaban:

64

Gunakan sensor ukuran dari pustaka css-element-queries:

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

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

Ia menggunakan pendekatan berbasis peristiwa dan tidak membuang waktu cpu Anda. Bekerja di semua browser termasuk IE7 +.

Marc J. Schmidt
sumber
5
solusi yang bagus, ia menggunakan elemen baru yang tidak terlihat sebagai overlay pada target yang diinginkan dan memanfaatkan event "scroll" pada overlay untuk memicu perubahan.
Eike Thies
2
Ini adalah satu-satunya solusi yang berfungsi dalam semua kasus, termasuk ketika konten dan atribut tidak berubah tetapi dimensi berubah (contoh: persentase dimensi menggunakan css)
FF_Dev
2
Solusi terbaik sejauh ini.
dlsso
1
Ini bukan jawaban pilihan utama di sini adalah sebuah tragedi. Ini benar-benar berfungsi 100%.
Jimbo Jonny
Ini tampaknya tidak berfungsi untuk elemen yang mulai tersembunyi.
greatwitenorth
48

Saya menulis sebuah plugin kadang-kadang kembali untuk pendengar attrchange yang pada dasarnya menambahkan fungsi pendengar pada perubahan atribut. Meskipun saya mengatakannya sebagai plugin, sebenarnya ini adalah fungsi sederhana yang ditulis sebagai plugin jQuery .. jadi jika Anda mau .. lepaskan kode plugin plugin dan gunakan fungsi inti.

Catatan: Kode ini tidak menggunakan polling

lihat demo sederhana ini 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();
});

Halaman plugin: http://meetselva.github.io/attrchange/

Versi yang diperkecil: (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)
Selvakumar Arumugam
sumber
25
Ini menyelesaikan masalah jika Anda mengubah ukuran div secara manual, ini tidak menyelesaikan pertanyaan awal, bukan? Jika Anda menambahkan konten secara dinamis, ia tidak mendeteksi perubahan ketinggian: jsfiddle.net/aD49d/25
smets.kevin
Saya juga tertarik untuk mengetahui apakah ada cara untuk membuat ini berfungsi untuk konten yang dinamis.
EricP
4
@ JoCoder Kode attrchange ini bergantung pada peristiwa DOM yang dipicu oleh browser saat ada aksi pengguna. Namun, konten dinamis dalam contoh itu dimasukkan secara terprogram yang sayangnya tidak memicu peristiwa apa pun. "Polling" tampaknya menjadi pilihan lain yang lebih mudah di sini .. opsi lain akan dapat memicu secara manual setelah konten dinamis disertakan.
Selvakumar Arumugam
28

Anda dapat menggunakan acara DOMSubtreeModified

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

Tetapi ini akan menyala bahkan jika dimensi tidak berubah, dan menugaskan kembali posisi kapan pun itu dapat membuat hit performa. Dalam pengalaman saya menggunakan metode ini, memeriksa apakah dimensi telah berubah lebih murah sehingga Anda dapat mempertimbangkan menggabungkan keduanya.

Atau jika Anda secara langsung mengubah div (daripada div yang diubah oleh input pengguna dengan cara yang tidak dapat diprediksi, seperti jika itu contentEditable), Anda bisa memecat suatu peristiwa khusus kapan pun Anda melakukannya.

Kelemahan: IE dan Opera tidak mengimplementasikan acara ini.

kelopak mata
sumber
12
IE & Opera tidak mengimplementasikan acara ini: quirksmode.org/dom/events/index.html
DEfusion
14
DomSubtreeModified dikecualikan
Adonis K. Kakoulidis
2
Cara modern untuk melakukan ini adalah dengan menggunakan MutationObserver: developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Christian Bankester
21

Inilah cara saya baru-baru ini menangani masalah ini:

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

Saya tahu saya terlambat beberapa tahun ke pesta, anggap saja jawaban saya dapat membantu beberapa orang di masa depan, tanpa harus mengunduh plugin apa pun.

Kyle
sumber
1
Saya kira dalam beberapa hal ini bukan cara terbaik untuk melakukannya, tetapi saya sebenarnya cukup menyukainya, karena itu berarti Anda dapat memicunya sebagai panggilan balik di akhir animasi. Plugin pengubahan ukuran akan terus menyala sepanjang animasi, yang bisa membantu, tetapi juga bisa menimbulkan masalah. Metode ini setidaknya memberi Anda kendali kapan harus memecat pemeriksaan ketinggian.
andyface
Apa sebenarnya kode Anda? Mengapa kita tidak bisa hanya menggunakan kode yang Anda tulis di dalam bind event dalam fungsi insted binding dan triggering?
user1447420
Tapi ini tidak otomatis, bukan?
Albert Català
17

Anda bisa menggunakan MutationObserverkelas.

MutationObservermemberikan pengembang cara untuk bereaksi terhadap perubahan dalam DOM. Ini dirancang sebagai pengganti Acara Mutasi yang ditentukan dalam spesifikasi Acara DOM3.

Contoh ( sumber )

// 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();
EFernandes
sumber
Ini jawaban yang benar. Lihat juga MutationSummary, perpustakaan yang dibangun di atas MutationObservers: github.com/rafaelw/mutation-summary
Christian Bankester
9

Ada plugin jQuery yang dapat menangani ini dengan sangat baik

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

di sini adalah demo dari itu dengan skenario yang berbeda tentang kapan perubahan ketinggian, jika Anda mengubah ukuran div berbatasan merah.

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

Val
sumber
Ini indah, tetapi bukankah secara default polling UI setiap milidetik untuk perubahan? Apakah itu efisien?
Michael Scott Cuthbert
1
@MichaelScottCuthbert Sudah lama ditulis, tetapi saya menggunakan setTimeout, jadi itu akan menjadi 1ms + [waktu yang diperlukan untuk melakukan pemeriksaan] singkatnya, tetapi idenya adalah untuk mendengarkan secara konstan, setelah Anda melakukan pemicunya lagi, seperti sebuah antrian. Saya yakin saya bisa melakukannya lebih baik tetapi tidak banyak waktu.
Val
Ah, ya, saya melihat Anda sekitar satu tahun sebelum solusi Vega (yang akhirnya saya gunakan) dan sebelum semua DOMSubtreeModified, dll. Pendengar didukung secara luas. Saya belajar banyak dari membaca kode Anda, jadi saya pikir ada baiknya menjaga tautan tetap tinggi.
Michael Scott Cuthbert
7

Menanggapi user007:

Jika ketinggian elemen Anda berubah karena item ditambahkan ke dalamnya menggunakan .append()Anda tidak perlu mendeteksi perubahan ketinggian. Cukup tambahkan reposisi elemen kedua Anda di fungsi yang sama di mana Anda menambahkan konten baru ke elemen pertama Anda.

Seperti dalam:

Contoh Kerja

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

Anda dapat membuat setInterval sederhana.

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

EDIT:

Ini adalah contoh dengan kelas. Tetapi Anda dapat melakukan sesuatu yang paling mudah.

Estefano Salazar
sumber
0

Anda dapat menggunakan ini, tetapi hanya mendukung Firefox dan Chrome.

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

Ronald Rivera
sumber
0

Cukup mendasar tetapi berfungsi:

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

jQuery(window).resize(function () {
    editoHeightSize();
});
Zac
sumber
ini hanya akan diaktifkan jika jendela diubah ukurannya, tetapi OP ingin mengikat acara pengubahan ukuran ke wadah tertentu
Fanie Void