jQueryを使用してdivの高さがいつ変化するかを検出する


141

動的に追加および削除されるコンテンツを含むdivがあるので、高さが頻繁に変化します。私はまた、JavaScriptの真下に絶対的に配置されたdivを持っているので、divの高さが変化したことを検出できない限り、divをその下に再配置することはできません。

では、そのdivの高さが変化したことをどのように検出できますか?使用する必要があるいくつかのjQueryイベントがあると思いますが、どちらにフックするかわかりません。


4
jQueryを使用するときにプラグインを使用したくないのはなぜでしょうか。
Andre

1
@ user007要素のサイズを変更する理由は何ですか?
A. Wolff 2013

@roasted divの高さは、いくつかの項目が追加されたときに変更され、追加はjqueryによって行われます
user007

1
@ user007したがって、DIVに何かを追加するときに、DIVのカスタムサイズ変更イベントをトリガーできます。もう1つの方法(最悪のIMO)は、ネイティブjqueryのappend()メソッドを単に拡張するコンテンツを追加するためのカスタムメソッドを使用し、コールバックで使用することです

@roastedヒントをありがとう。
user007 2013

回答:


64

css-element-queriesライブラリのサイズ変更センサーを使用します。

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

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

イベントベースのアプローチを使用し、CPU時間を無駄にしません。含むすべてのブラウザで動作します。IE7 +。


5
優れたソリューションであり、非表示の新しい要素を目的のターゲットのオーバーレイとして使用し、オーバーレイの「スクロール」イベントを利用して変更をトリガーします。
Eike Thies 14年

2
これは、コンテンツと属性は変更されないが寸法は変更される場合(例:cssを使用したパーセント寸法)を含む、すべてのケースで機能する唯一のソリューション
FF_Dev

2
最高のソリューションです。
dlsso

1
ここで投票された回答のトップではないのは悲劇です。これは本当に100%機能します。
神保ジョニー

これは、非表示で始まる要素に対しては機能しないようです。
greatwitenorth 2017

48

私はattrchangeリスナー用のプラグインを書き戻しましたが、これは基本的に属性の変更時にリスナー関数を追加します。私はそれをプラグインと言いますが、実際にはjQueryプラグインとして記述された単純な関数です。したがって、必要に応じて..プラグイン固有のコードを取り除き、コア関数を使用します。

注:このコードはポーリングを使用しません

この簡単なデモをチェックしてください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

また、動的なコンテンツでこれを機能させる方法があったかどうかも知りたいです。
EricP 2013

4
@JoeCoderこのattrchangeコードは、ユーザーアクションがあるときにブラウザによってトリガーされるDOMイベントに依存します。ただし、その例の動的コンテンツはプログラムで含まれているため、残念ながらイベントはトリガーされません。「ポーリング」はもう1つの簡単なオプションのようです。他のオプションは、動的コンテンツが含まれた後に手動でトリガーできます。
Selvakumar Arumugam 2013

28

DOMSubtreeModifiedイベントを使用できます

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

しかし、これは寸法が変わらない場合でも発生し、発生するたびに位置を再割り当てすると、パフォーマンスが低下する可能性があります。この方法を使用した私の経験では、寸法が変更されたかどうかを確認する方が安価であるため、この2つを組み合わせることを検討してください。

あるいは、divを直接変更している場合(divがcontentEditableのようにユーザー入力によって予測できない方法で変更されるのではなく)、そうするたびにカスタムイベントを発生させるだけで済みます。

欠点:IEとOperaはこのイベントを実装していません。


12
IEとOperaはこのイベントを実装していません:quirksmode.org/dom/events/index.html
DEfusion

14
DomSubtreeModifiedの価格が下がりました
アドニスK.カクリディス

2
:これを行うには近代的な方法は、MutationObserver使用することですdeveloper.mozilla.org/en-US/docs/Web/API/MutationObserver
クリスチャン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 2013

あなたのコードは正確には何をしていますか?バインドとトリガーの機能を備えた関数でbindイベント内に記述したコードを使用できないのはなぜですか?
user1447420

しかし、これは自動的ではありませんね。
AlbertCatalà15年

17

MutationObserverクラスを使用できます。

MutationObserverDOMの変更に対応する方法を開発者に提供します。これは、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();

これが正解です。MutationObserversに基づいて構築されたライブラリであるMutationSummaryもご覧ください
Christian Bankester '30 / 09/30

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

ああ、はい、あなたはVegaのソリューション(私が最終的に使用したもの)の前、およびすべてのDOMSubtreeModifiedなどのリスナーが広くサポートされる前の約1年だったと思います。でもコードを読んでたくさんのことを学んだので、リンクを維持しておく価値はあると思います。
Michael Scott Cuthbert

7

user007への応答:

アイテムが要素に追加されたために要素の高さが変化している場合、高さの.append()変化を検出する必要はありません。新しいコンテンツを最初の要素に追加するのと同じ関数で、2番目の要素の再配置を追加するだけです。

のように:

実例

$('.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.