Phát hiện khi chiều cao của div thay đổi bằng jQuery


141

Tôi đã có một div chứa một số nội dung được thêm và xóa một cách linh hoạt, vì vậy chiều cao của nó đang thay đổi thường xuyên. Tôi cũng có một div được định vị tuyệt đối ngay bên dưới javascript, vì vậy trừ khi tôi có thể phát hiện khi chiều cao của div thay đổi, tôi không thể định vị lại div bên dưới nó.

Vậy, làm thế nào tôi có thể phát hiện khi chiều cao của div đó thay đổi? Tôi giả sử có một số sự kiện jQuery tôi cần sử dụng, nhưng tôi không chắc chắn nên chọn cái nào.


4
Tôi tự hỏi tại sao người ta không muốn sử dụng plugin khi sử dụng jQuery.
Andre Calil

1
@ user007 Điều gì làm cho kích thước các yếu tố của bạn thay đổi?
A. Wolff

@roiled thay đổi chiều cao div của tôi khi một số mặt hàng được thêm vào nó, việc nối thêm được thực hiện bởi jquery
user007

1
@ user007 vì vậy khi bạn thêm một cái gì đó vào DIV, bạn có thể kích hoạt một sự kiện thay đổi kích thước tùy chỉnh cho DIV. Một cách khác (tồi tệ nhất IMO) có thể được sử dụng một phương pháp tùy chỉnh cho phụ nội dung mà chỉ đơn giản mở rộng phương pháp có nguồn gốc jquery append (), sử dụng nó với một callback ví dụ
A. Wolff

@roiled Cảm ơn vì tiền boa.
dùng007

Câu trả lời:


64

Sử dụng cảm biến thay đổi kích thước từ thư viện truy vấn phần tử css:

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

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

Nó sử dụng một cách tiếp cận dựa trên sự kiện và không lãng phí thời gian cpu của bạn. Hoạt động trong tất cả các trình duyệt bao gồm. IE7 +.


5
giải pháp hay, nó sử dụng một yếu tố mới vô hình làm lớp phủ trên mục tiêu mong muốn và sử dụng sự kiện "cuộn" trên lớp phủ để kích hoạt các thay đổi.
Eike Thies

2
Đây là giải pháp duy nhất hoạt động trong mọi trường hợp, kể cả khi nội dung và thuộc tính không thay đổi nhưng kích thước thay đổi (ví dụ: kích thước phần trăm sử dụng css)
FF_Dev

2
Giải pháp tốt nhất cho đến nay.
dlsso

1
Đây không phải là câu trả lời được bình chọn hàng đầu ở đây là một thảm kịch. Điều này thực sự hoạt động 100%.
Jimbo Jonny

Điều này dường như không hoạt động đối với các yếu tố bắt đầu ẩn.
greatwitenorth

48

Thỉnh thoảng tôi đã viết một plugin cho người nghe attrchange về cơ bản thêm chức năng nghe vào thay đổi thuộc tính. Mặc dù tôi nói nó là một plugin, nhưng thực ra nó là một hàm đơn giản được viết dưới dạng plugin jQuery .. vì vậy nếu bạn muốn .. hãy loại bỏ mã specfic của plugin và sử dụng các hàm cốt lõi.

Lưu ý: Mã này không sử dụng bỏ phiếu

xem bản demo đơn giản này 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();
});

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

Phiên bản rút gọn: (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
Điều này giải quyết vấn đề nếu bạn thay đổi kích thước div theo cách thủ công, điều này không giải quyết được câu hỏi ban đầu phải không? Nếu bạn thêm nội dung một cách linh hoạt, nó sẽ không phát hiện sự thay đổi chiều cao: jsfiddle.net/aD49d/25
smets.kevin

Tôi cũng sẽ quan tâm đến việc nếu có một cách để làm cho công việc này cho nội dung động.
EricP

4
@JoeCoder Mã attrchange này dựa trên các sự kiện DOM được trình duyệt kích hoạt khi có hành động của người dùng. Tuy nhiên, nội dung động trong ví dụ đó được bao gồm theo chương trình mà không may không kích hoạt bất kỳ sự kiện nào. "Bỏ phiếu" dường như là một tùy chọn dễ dàng hơn ở đây .. tùy chọn khác sẽ có thể kích hoạt thủ công sau khi bao gồm nội dung động.
Selvakumar Arumugam

28

Bạn có thể sử dụng sự kiện DOMSubtreeModified

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

Nhưng điều này sẽ kích hoạt ngay cả khi kích thước không thay đổi và chỉ định lại vị trí bất cứ khi nào nó bắn có thể gây ra hiệu suất. Theo kinh nghiệm của tôi khi sử dụng phương pháp này, kiểm tra xem kích thước đã thay đổi có ít tốn kém hơn hay không và vì vậy bạn có thể cân nhắc kết hợp cả hai.

Hoặc nếu bạn đang trực tiếp thay đổi div (thay vì div bị thay đổi bởi đầu vào của người dùng theo những cách không thể đoán trước, như nếu đó là nội dung có thể chỉnh sửa), bạn có thể chỉ cần kích hoạt một sự kiện tùy chỉnh bất cứ khi nào bạn làm như vậy.

Nhược điểm: IE và Opera không triển khai sự kiện này.


12
IE & Opera không triển khai sự kiện này: quirksmode.org/dom/events/index.html
DEfusion

14
DomSubtreeModified đã bị trục xuất
Adonis K. Kakoulidis

2
Cách hiện đại để thực hiện việc này là sử dụng
MutingObserver

21

Đây là cách tôi mới xử lý vấn đề này:

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

Tôi biết tôi đến bữa tiệc muộn vài năm, chỉ cần nghĩ rằng câu trả lời của tôi có thể giúp một số người trong tương lai mà không phải tải xuống bất kỳ plugin nào.


1
Tôi đoán theo một số cách đây không phải là cách tốt nhất để làm điều đó, nhưng tôi thực sự rất thích nó, vì nó có nghĩa là bạn có thể kích hoạt nó như một cuộc gọi lại ở cuối hoạt hình. Plugin thay đổi kích thước sẽ tiếp tục bắn trong suốt một hình ảnh động, điều này có thể hữu ích, nhưng cũng có thể gây ra vấn đề. Phương pháp này ít nhất giúp bạn kiểm soát thời điểm bắn kiểm tra chiều cao.
andyface

Chính xác thì mã của bạn làm gì? Tại sao chúng ta không thể sử dụng mã bạn viết bên trong sự kiện liên kết trong hàm do liên kết và kích hoạt?
dùng1447420

Nhưng điều này không tự động, phải không?
Albert Català

16

Bạn có thể sử dụng MutationObserverlớp.

MutationObservercung cấp cho các nhà phát triển một cách để phản ứng với những thay đổi trong DOM. Nó được thiết kế để thay thế cho Sự kiện Đột biến được xác định trong đặc tả Sự kiện DOM3.

Ví dụ ( nguồn )

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

Đây là câu trả lời chính xác. Ngoài ra, hãy xem MutingSummary, một thư viện được xây dựng trên
MutingObservers

9

Có một plugin jQuery có thể xử lý vấn đề này rất tốt

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

Đây là bản demo của nó với các kịch bản khác nhau khi thay đổi chiều cao, nếu bạn thay đổi kích thước div viền đỏ.

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


Nó đẹp, nhưng mặc định nó không thăm dò giao diện người dùng mỗi mili giây để thay đổi? Có hiệu quả không?
Michael Scott Cuthbert

1
@MichaelScottCuthbert Nó đã được viết cách đây rất lâu, nhưng tôi đã sử dụng setTimeout, vì vậy sẽ mất 1ms + [thời gian cần thiết để kiểm tra], nhưng ý tưởng là nghe liên tục, một khi bạn đã kích hoạt lại, nó giống như một hàng đợi Tôi chắc chắn rằng tôi có thể làm điều đó tốt hơn rất nhiều nhưng không có nhiều thời gian.
Val

À, vâng, tôi thấy rằng bạn đã ở khoảng một năm trước khi giải pháp của Vega (mà cuối cùng tôi đã sử dụng) và trước tất cả các DOMSubtreeModified, v.v. người nghe được hỗ trợ rộng rãi. Tôi đã học được rất nhiều từ việc đọc mã của bạn, vì vậy tôi nghĩ rằng nó đáng để duy trì các liên kết.
Michael Scott Cuthbert

7

Đáp lại user007:

Nếu chiều cao của phần tử của bạn thay đổi do các mục được gắn vào phần tử đó, .append()bạn không cần phải phát hiện sự thay đổi về chiều cao. Chỉ cần thêm vị trí của phần tử thứ hai của bạn trong cùng chức năng nơi bạn đang nối thêm nội dung mới vào phần tử đầu tiên.

Như trong:

Ví dụ làm việc

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

2

Bạn có thể tạo một setInterval đơn giản.

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

BIÊN TẬP:

Đây là một ví dụ với một lớp. Nhưng bạn có thể làm một cái gì đó dễ dàng nhất.


0

Bạn có thể sử dụng cái này, nhưng nó chỉ hỗ trợ Firefox và Chrome.

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


0

Khá cơ bản nhưng hoạt động:

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

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

điều này sẽ chỉ được kích hoạt nếu cửa sổ được thay đổi kích thước, nhưng OP muốn liên kết một sự kiện thay đổi kích thước với một thùng chứa cụ thể
Fanie Void
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.