DIVのディメンションの変更を検出する方法は?


351

私は次のサンプルhtmlを持っています、100%幅のDIVがあります。いくつかの要素が含まれています。ウィンドウのサイズ変更を実行しているときに、内部要素の位置が変更され、divの寸法が変わる場合があります。divのディメンション変更イベントをフックできるかどうかを尋ねています。そしてそれを行う方法?現在、コールバック関数をターゲットDIVのjQuery resizeイベントにバインドしていますが、コンソールログが出力されません。以下を参照してください。

サイズ変更前 ここに画像の説明を入力してください

<html>
<head>
    <script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" language="javascript">
            $('#test_div').bind('resize', function(){
                console.log('resized');
            });
    </script>
</head>
<body>
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
    </div>
</body>
</html>

7
サイズ変更イベントを指定されたdiv要素にバインドしているため、これは機能しません。ただし、サイズ変更イベントは、要素ではなくウィンドウに対してトリガーされます。
Fatih Acet、2011年

setInterval可能な解決策としてここを使用できます。clearInterval作業が完了したら、いつでもボタンクリックにバインドしてループを停止できます。
Peter Darmis 2016年

1
2020年以降、ResizeObserverは IEを除くすべての主要ブラウザー(Chrome、Safari、Firefox、Edge)で動作します。caniuse.com/#feat=resizeobserver
Dan

回答:


264

要素のサイズが変更されたかどうかを判断する非常に効率的な方法があります。

http://marcj.github.io/css-element-queries/

このライブラリには、ResizeSensorサイズ変更の検出に使用できるクラスがあります。
イベントベースのアプローチを使用しているため、非常に高速で、CPU時間を無駄にしません。

例:

new ResizeSensor(jQuery('#divId'), function(){ 
    console.log('content dimension changed');
});

jQuery onresizeプラグインsetTimeout()は、DOM clientHeight/ clientWidthプロパティをループで読み取ることと組み合わせて使用して変更を確認するため、使用しないでください。レイアウトのスラッシングを引き起こす
ため、これは信じられないほど遅くて不正確です。

開示:私はこのライブラリに直接関係しています。


8
@ jake、IE11サポートが実装されました。
マークJ.シュミット

15
@Aletheiosをよく見てください。requestAnimationFrameは、遅い次元の検出用ではありませんが、正反対です。CPUベースの時間を節約するために、実際のイベントベースのサイズ変更センサーによって発生する極端な数のイベントをすべて平滑化します。github.com/marcj/css-element-queries/blob/master/src/…で
Marc J. Schmidt

6
@Aletheiosポイントを逃したと思います:setTimeoutは不正確であるだけでなく、非常に遅いです。単純なブール値をチェックするrequestAnimationFrameは、DOMプロパティに対して常にチェックするsetTimeoutよりも桁違いに高速です。それに加えて、setTimeoutは数ミリ秒ごとに呼び出されます。
マークJ.シュミット

9
@Orwellophile明らかに何も理解していません。内部でどのように機能するかわからない場合は、回答の反対投票をやめます。繰り返しますが、css-element-query:ディメンションが変更されるたびにトリガーされる実際のサイズ変更イベントを使用します。あまりにも多くのイベント(ドラッグアンドドロップなど)を取得するため、トリガーされたイベントを1 /フレームに平滑化する単純なブール変数のrequestAnimationFrameチェックを追加しました。jqueryプラグイン:DOMレイアウトの小道具(clientHeightなど)を常にチェックするsetTimeoutを使用します。各チェックは非常に低速ですが、同じ機能を持つために頻繁にチェックする必要があります。
マークJ.シュミット

9
@ Aletheios、@ Orwellophile、およびそれらによって誤解された可能性のある人:requestAnimationFramevs setTimeoutは無関係であり、このライブラリはループしませんrequestAnimationFrameコールバックを呼び出す頻度をデバウンス/スロットルするためにのみ使用され、ポーリングしません。MutationObserverは、これとは異なり、理論的には同様の効果で使用できますが、古いブラウザーでは使用できません。これは非常に賢いです。
Han Seoul-Oh

251

この新しい標準は、Chrome 64で利用可能なResize Observer apiです。

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me</textarea><br>

オブザーバーのサイズ変更

仕様:https : //wicg.github.io/ResizeObserver

ポリフィル:https : //github.com/WICG/ResizeObserver/issues/3

Firefoxの問題:https : //bugzil.la/1272409

Safariの問題:http : //wkb.ug/157743

現在のサポート:http : //caniuse.com/#feat=resizeobserver


3
現在のところ、Chromeのみがサポートしているため、本番サイトにはまだ役立ちません。しかし、間違いなくここで最高のソリューションです!ところで、実装ステータスの概要は次のとおりです:chromestatus.com/feature/5705346022637568
Philipp

8
@Philippポリフィルがあります。
Daniel Herr

2
すべてのブラウザでまだ実験的な機能であるようですcaniuse.com/#feat=resizeobserver
Francesc Rosas

5
この回答から2年経っても、ブラウザのサポートは厳しい
Scrimothy

2
最新のChromeとFFの魅力のように動作します。
KlemenTušar19年

32

resizeイベントは、window一般的なhtml要素ではなく、オブジェクトにバインドする必要があります。

次にこれを使用できます:

$(window).resize(function() {
    ...
});

コールバック関数内で、div呼び出しの新しい幅を確認できます

$('.a-selector').width();

したがって、あなたの質問に対する答えは「いいえ」ですresize。イベントをdivにバインドすることはできません。


124
この答えは十分ではありません。ウィンドウのサイズを変更しないと、サイズが変更される場合があります。まったく。
vsync

9
たとえば、splitter要素がある場合や、要素にテキストやその他のコンテンツを追加する場合などです。
ギュンターZöchbauer

@anuは当てはまりません。たとえば、JavaScriptを介してDOMを変更すると、CSSが新しい構造に適用され、レイアウトが異なります-すべてのコンテナーのサイズ。
Antoniossss

29

長期的には、ResizeObserverを使用できるようになります。

new ResizeObserver(callback).observe(element);

残念ながら、現在多くのブラウザではデフォルトでサポートされていません。

とりあえず、以下のような機能が使えます。なぜなら、要素サイズの変更の大部分は、ウィンドウのサイズ変更またはDOM内の何かの変更によるものです。ウィンドウのサイズ変更イベントでウィンドウのサイズ変更をリッスンでき、MutationObserverを使用してDOMの変更をリッスンできます

これらのイベントのいずれかの結果として、提供された要素のサイズが変更されたときにコールバックする関数の例を次に示します。

var onResize = function(element, callback) {
  if (!onResize.watchedElementData) {
    // First time we are called, create a list of watched elements
    // and hook up the event listeners.
    onResize.watchedElementData = [];

    var checkForChanges = function() {
      onResize.watchedElementData.forEach(function(data) {
        if (data.element.offsetWidth !== data.offsetWidth ||
            data.element.offsetHeight !== data.offsetHeight) {
          data.offsetWidth = data.element.offsetWidth;
          data.offsetHeight = data.element.offsetHeight;
          data.callback();
        }
      });
    };

    // Listen to the window's size changes
    window.addEventListener('resize', checkForChanges);

    // Listen to changes on the elements in the page that affect layout 
    var observer = new MutationObserver(checkForChanges);
    observer.observe(document.body, { 
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true 
    });
  }

  // Save the element we are watching
  onResize.watchedElementData.push({
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  });
};

1
残念ながら、MutationObserverはShadow DOMの変更を検出できないようです。
Ajedi32 2015年

@nkron、残念ながら、CSS3 resizeを使用する場合、ユーザーが手動でサイズを変更すると、サイズ変更が発生する可能性があります。このイベントはキャッチできません。
パセリエ2016

@ Ajedi32はい。ただし、ShadowDOM内でMutationObserverを使用できます。つまりbody、この例のようにを監視する代わりに、要素を直接監視できます。それは実際に全身を見るよりもパフォーマンスが高く効率的です。
trusktr 2016

@ Ajedi32さて、唯一の問題は、Shadow DOMツリーが閉じている場合、内部にアクセスできなくなることですが、通常、これを実行する必要があるとは思いません。このような閉じたツリーは、デザインに問題がある可能性があります。理想的には、アクセスできる独自の要素のみを観察する必要があります。内部のサイズを確認する必要があるShadow-DOMコンポーネントは、適切に設計されていない可能性があります。具体的な例はありますか?もしそうなら、多分私は解決策を提案するのを手伝うことができます(私もそれに興味がありますが、まだ例がないため)
trusktr

@trusktr現在のところMCVEはありませんが、基本的には、ユーザー入力の結果としてサイズを変更できるShadow DOM要素があれば十分です。たとえば、クリックされたときにいくつかの追加情報が表示されるボックス。個々の要素ではなく、ページを監視していることに注意してください。理由に関係なく、ページのサイズが大きくなったときに自動的に下にスクロールしたいからです。Shadow DOM要素の拡張は、ページが長くなる可能性がある多くの理由の1つにすぎません。
Ajedi32 16

24

ResizeSensor.jsは巨大なライブラリの一部ですが、私はにその機能を減少THIS

function ResizeSensor(element, callback)
{
    let zIndex = parseInt(getComputedStyle(element));
    if(isNaN(zIndex)) { zIndex = 0; };
    zIndex--;

    let expand = document.createElement('div');
    expand.style.position = "absolute";
    expand.style.left = "0px";
    expand.style.top = "0px";
    expand.style.right = "0px";
    expand.style.bottom = "0px";
    expand.style.overflow = "hidden";
    expand.style.zIndex = zIndex;
    expand.style.visibility = "hidden";

    let expandChild = document.createElement('div');
    expandChild.style.position = "absolute";
    expandChild.style.left = "0px";
    expandChild.style.top = "0px";
    expandChild.style.width = "10000000px";
    expandChild.style.height = "10000000px";
    expand.appendChild(expandChild);

    let shrink = document.createElement('div');
    shrink.style.position = "absolute";
    shrink.style.left = "0px";
    shrink.style.top = "0px";
    shrink.style.right = "0px";
    shrink.style.bottom = "0px";
    shrink.style.overflow = "hidden";
    shrink.style.zIndex = zIndex;
    shrink.style.visibility = "hidden";

    let shrinkChild = document.createElement('div');
    shrinkChild.style.position = "absolute";
    shrinkChild.style.left = "0px";
    shrinkChild.style.top = "0px";
    shrinkChild.style.width = "200%";
    shrinkChild.style.height = "200%";
    shrink.appendChild(shrinkChild);

    element.appendChild(expand);
    element.appendChild(shrink);

    function setScroll()
    {
        expand.scrollLeft = 10000000;
        expand.scrollTop = 10000000;

        shrink.scrollLeft = 10000000;
        shrink.scrollTop = 10000000;
    };
    setScroll();

    let size = element.getBoundingClientRect();

    let currentWidth = size.width;
    let currentHeight = size.height;

    let onScroll = function()
    {
        let size = element.getBoundingClientRect();

        let newWidth = size.width;
        let newHeight = size.height;

        if(newWidth != currentWidth || newHeight != currentHeight)
        {
            currentWidth = newWidth;
            currentHeight = newHeight;

            callback();
        }

        setScroll();
    };

    expand.addEventListener('scroll', onScroll);
    shrink.addEventListener('scroll', onScroll);
};

それの使い方:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});

これがチャートが行うことです。
Antoniossss

それを圧縮してくれてありがとう。私はそれを試してみるつもりです:)
トニーK.

この表現に欠けているものがありますparseInt( getComputedStyle(element) )
GetFree

2
「let zIndex = parseInt(getComputedStyle(element));」とはどういうふうに混乱します。有効ですか?「let zIndex = parseInt(getComputedStyle(element).zIndex);
Ryan Badour

1
上記のソリューション/コードはすべてのサイズ変更イベントを検出しません(たとえば、コンテナーが固定サイズに変更された場合、コンテナーが子イベントのサイズ変更を検出しません。jsfiddle.net/8md2rfsy/1を参照してください)。受け入れられた回答は機能します(それぞれの行のコメントを外します)。
newBee

21

setTimeout()パフォーマンスが低下するため、ハッキングはお勧めしません。代わりに、Divサイズの変更をリッスンするためにDOMミューテーションオブザーバーを使用できます 。

JS:

var observer = new MutationObserver(function(mutations) {
    console.log('size changed!');
  });
  var target = document.querySelector('.mydiv');
  observer.observe(target, {
    attributes: true
  });

HTML:

<div class='mydiv'>
</div>

ここにフィドル
がありますdivサイズを変更してみてください。


さらにメソッドをメソッドにラップして、debounce効率を向上させることができます。debounceDIVがサイズ変更されているミリ秒ごとにトリガーするのではなく、xミリ秒ごとにメソッドをトリガーします。


9
この問題の唯一の問題は、要素に実際に変更が発生しない限り、変更が報告されないことです。他の要素が追加されたために要素のサイズが変更された場合、これは機能しません。
Tony K.

@TonyKに同意します。これがMutationObserverに関する私の唯一の問題であり、要素のサイズ変更ライブラリを探しています
Murhaf Sousli

@JerryGoyal divに<img>タグが含まれていると機能しません。最初の例では、画像は読み込まれず、divサイズが0に設定され、読み込み後にdivサイズが変更されますが、オブザーバーはトリガーされません
Santhosh

15

最善の解決策は、いわゆるElement Queriesを使用することです。ただし、これらは標準ではなく、仕様もありません。この方法を使用する場合、唯一のオプションは、利用可能なポリフィル/ライブラリの1つを使用することです。

要素クエリの背後にある考え方は、ページ上の特定のコンテナが、そこに提供されているスペースに応答できるようにすることです。これにより、コンポーネントを1回書き込んでから、ページ上の任意の場所にドロップできるようになりますが、コンテンツは現在のサイズに調整されます。ウィンドウのサイズに関係なく。これは、要素クエリとメディアクエリの最初の違いです。ある時点で、要素クエリ(または同じ目標を達成するもの)を標準化し、ネイティブでクリーンでシンプルかつ堅牢な仕様が作成されることを誰もが望んでいます。ほとんどの人は、メディアクエリが非常に制限されており、モジュール設計と真の応答性に役立たないことに同意します。

さまざまな方法で問題を解決するいくつかのポリフィル/ライブラリがあります(ただし、解決策ではなく回避策と呼ばれる場合があります)。

同様の問題に対する他の解決策が提案されました。通常、タイマーまたは内部でウィンドウ/ビューポートのサイズを使用しますが、これは実際のソリューションではありません。さらに、理想的には、これはJavaScriptまたはHTMLではなく、主にCSSで解決する必要があると思います。


要素クエリの+1ですが、すぐに表示されるとは思いません。この時点ではまだドラフト仕様はありませんAFAIK ...多分私たちの利害関係者の1人がまとめて提出する必要がありますか?
Rob Evans

1
もちろんそれは良い考えです。最終バージョンに到達するには長い時間がかかります。多くの注意を引く必要があります。これを良い方法で設計することは、私にとって簡単なことではないようです。ブラウザ間の互換性、循環依存、デバッグ、読みやすさ、メンテナンスなど。できるだけ早く始めましょう:)
Stan

@スタン、私はこの答えは、要素クエリが何であるかについての詳細を追加することでより良いものになると思います。
Pacerier、2016

15

MarcJのソリューションが機能しなかったときに、このライブラリが機能することがわかりました。

https://github.com/sdecima/javascript-detect-element-resize

これは非常に軽量で、CSSまたは単にHTMLのロード/レンダリングによって、自然なサイズ変更も検出します。

コードサンプル(リンクから取得):

<script type="text/javascript" src="detect-element-resize.js"></script>
<script type="text/javascript">
  var resizeElement = document.getElementById('resizeElement'),
      resizeCallback = function() {
          /* do something */
      };
  addResizeListener(resizeElement, resizeCallback);
  removeResizeListener(resizeElement, resizeCallback);
</script>

これだよ。147行、スクロールイベントを使用します。divディメンションの変更を最適に検出する方法についての完全で真の答えが必要な場合は、このコードに目を通してください。ヒント:「このライブラリを使用する」だけではありません。
Seph Reed 2016

1
このライブラリを試す前に、この問題を確認する必要があります。
Louis

13

これを見てくださいhttp://benalman.com/code/projects/jquery-resize/examples/resize/

様々な例があります。ウィンドウのサイズを変更して、コンテナ要素内の要素がどのように調整されるかを確認してください。

それを動作させる方法を説明するjsフィドルの例
このフィドルをご覧くださいhttp://jsfiddle.net/sgsqJ/4/

そのresize()イベントでは、クラス「test」を持つ要素とウィンドウオブジェクトにバインドされ、ウィンドウオブジェクトのサイズ変更コールバックでは$( '。test')。resize()が呼び出されます。

例えば

$('#test_div').bind('resize', function(){
            console.log('resized');
});

$(window).resize(function(){
   $('#test_div').resize();
});

面白い。そのjsfiddleは、インスペクターが開いている状態でChromeを常にクラッシュさせ、「テキストを追加」リンクをクリックします。Firefoxは「再帰が多すぎます」エラーをスローします。
EricP 2013

3
jQueryのサイズ変更プラグインは使用しないでください。それは本当に遅く、正確でもありません。より良い解決策を得るために私の答えを見てください。
マークJ.シュミット

24
これは、寸法の変更を直接検出しません。これは、サイズ変更イベントリスナーの副産物にすぎません。ディメンションの変更は、他の多くの方法で発生する可能性があります。
vsync

4
divのサイズ変更がスタイルやdomの変更によるもので、ウィンドウのサイズ変更によるものではない場合はどうなりますか?
2015

9

あなたは使用することができますiframeまたはobject使用contentWindowまたはcontentDocumentサイズ変更に。なしsetIntervalsetTimeout

手順:

  1. 要素の位置を relative
  2. 透明な絶対非表示IFRAME内に追加
  3. 聞くIFRAME.contentWindow- onresizeイベント

HTMLの例:

<div style="height:50px;background-color:red;position:relative;border:1px solid red">
<iframe style=width:100%;height:100%;position:absolute;border:none;background-color:transparent allowtransparency=true>
</iframe>
This is my div
</div>

JavaScript:

$('div').width(100).height(100);
$('div').animate({width:200},2000);

$('object').attr({
    type : 'text/html'
})
$('object').on('resize,onresize,load,onload',function(){
    console.log('ooooooooonload')
})

$($('iframe')[0].contentWindow).on('resize',function(){
    console.log('div changed')
})

実行例

JsFiddle:https ://jsfiddle.net/qq8p470d/


続きを見る:


1
jqueryを使用しない場合の注意事項はIFRAME.contentWindowonloadイベントがiframeで発生するまで利用できません。また、visibility:hidden;iframeは背後にある要素へのマウス入力をブロックできるため、スタイルを追加することもできます(少なくともIEでは「フローティング」しているようです)。
James Wilkins、2016年

3
これは機能しますが、サイズの変化を観察するためだけにまったく新しいブラウジングコンテキストを作成するオーバーヘッドがある重いソリューションです。また、場合によってdisplayは、要素のプロパティを変更することが理想的または実現不可能です。
trusktr

同意された、これは上記の恐ろしい解決策です
29er

どのようにひどい解決策を書いたのですか?
Aminadav Glickshtein

この方法は、動的なコンテンツのサイズ変更が必要なビデオプレーヤーやオーディオプレーヤーでうまく機能します。私はこのメソッドを使用してwavesurfer.js出力のサイズを変更します。
David Clews

8

ウィンドウオブジェクトのみが「サイズ変更」イベントを生成します。私があなたがしたいことをするために知っている唯一の方法は、定期的にサイズをチェックするインターバルタイマーを実行することです。


7

var div = document.getElementById('div');
div.addEventListener('resize', (event) => console.log(event.detail));

function checkResize (mutations) {
    var el = mutations[0].target;
    var w = el.clientWidth;
    var h = el.clientHeight;
    
    var isChange = mutations
      .map((m) => m.oldValue + '')
      .some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);

    if (!isChange)
      return;

    var event = new CustomEvent('resize', {detail: {width: w, height: h}});
    el.dispatchEvent(event);
}

var observer = new MutationObserver(checkResize); 
observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
#div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
<div id = "div">DIV</div>


7

この問題と同じくらい古く、これはほとんどのブラウザで依然として問題です。

他の人が言ったように、Chrome 64+にはResize Observesがネイティブで同梱されるようになりましたが、仕様はまだ微調整中であり、Chromeは現在(2019-01-29現在)仕様の最新版よりも遅れています。

私はいくつかの優れたResizeObserverポリフィルを実際に見かけましたが、一部は厳密に仕様に準拠しておらず、他は計算上の問題があります。

どのようなアプリケーションでも使用できるいくつかのレスポンシブWebコンポーネントを作成するために、私はこの振る舞いを切実に必要としていました。それらを適切に機能させるには、常に寸法を知る必要があるため、ResizeObserversは理想的に聞こえるので、仕様にできる限り近いポリフィルを作成することにしました。

リポジトリ:https : //github.com/juggle/resize-observer

デモ:https : //codesandbox.io/s/myqzvpmmy9


これは間違いなく、IE11 +ブラウザーの互換性を扱うすべての人にとって悩みの種です。
ekfuhrmann

3

Clay.js(https://github.com/zzarcon/clay)を使用すると、要素サイズの変更を検出するのは非常に簡単です。

var el = new Clay('.element');

el.on('resize', function(size) {
    console.log(size.height, size.width);
});

7
それがあなたのライブラリであることを考慮して、適切な開示を提供してください。
jhpratt GOFUNDME RELICENSING '19年

これは私にとってはうまくいきましたが、ResizeSensorはそうではありませんが、それは私のモーダルスタイルを壊します。ありがとうZzarcon :)
マキシマAlekz

3

このブログ投稿は、DOM要素のサイズ変更を効率的に検出するのに役立ちました。

http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

このコードの使い方...

AppConfig.addResizeListener(document.getElementById('id'), function () {
  //Your code to execute on resize.
});

例で使用されているパッケージコード...

var AppConfig = AppConfig || {};
AppConfig.ResizeListener = (function () {
    var attachEvent = document.attachEvent;
    var isIE = navigator.userAgent.match(/Trident/);
    var requestFrame = (function () {
        var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
            function (fn) { return window.setTimeout(fn, 20); };
        return function (fn) { return raf(fn); };
    })();

    var cancelFrame = (function () {
        var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
               window.clearTimeout;
        return function (id) { return cancel(id); };
    })();

    function resizeListener(e) {
        var win = e.target || e.srcElement;
        if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
        win.__resizeRAF__ = requestFrame(function () {
            var trigger = win.__resizeTrigger__;
            trigger.__resizeListeners__.forEach(function (fn) {
                fn.call(trigger, e);
            });
        });
    }

    function objectLoad(e) {
        this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
        this.contentDocument.defaultView.addEventListener('resize', resizeListener);
    }

    AppConfig.addResizeListener = function (element, fn) {
        if (!element.__resizeListeners__) {
            element.__resizeListeners__ = [];
            if (attachEvent) {
                element.__resizeTrigger__ = element;
                element.attachEvent('onresize', resizeListener);
            } else {
                if (getComputedStyle(element).position === 'static') element.style.position = 'relative';
                var obj = element.__resizeTrigger__ = document.createElement('object');
                obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
                obj.__resizeElement__ = element;
                obj.onload = objectLoad;
                obj.type = 'text/html';
                if (isIE) element.appendChild(obj);
                obj.data = 'about:blank';
                if (!isIE) element.appendChild(obj);
            }
        }
        element.__resizeListeners__.push(fn);
    };

    AppConfig.removeResizeListener = function (element, fn) {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            if (attachEvent) element.detachEvent('onresize', resizeListener);
            else {
                element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
                element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
            }
        }
    }
})();

注:AppConfigは、再利用可能な関数を整理するために使用する名前空間/オブジェクトです。名前を自由に検索して、好きな名前に置き換えてください。


3

私のjQueryプラグインは、だけでなく、すべての要素で「サイズ変更」イベントを有効にしますwindow

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 

1
リンクは存在しない場所を指しています。プラグインの名前を検索したところ、あなたの説明に対応するページが見つかりました。あなたはプラグインの作成者のようですので、私はあなたの回答の言語を編集して、これがあなたの作品であることを明示しました。このサイトのルールは、自分が開発したものを使用することを推奨する回答を書くときは、関係を明示的にする必要があるというものです。
ルイ、

setTimerで関数を何度も繰り返し実行するため、これは優れたソリューションではありません。つまり、何も起こらなくても、ブラウザーは常にCPUを消費しています。ラップトップと携帯電話の所有者は、onScrollイベントを使用するなどのアクションがある場合にのみブラウザイベントを使用するソリューションからメリットを得ます。
Roman Zenka 2018年

2

次のスニペットのコードを試すことができます。プレーンなJavaScriptを使用してニーズをカバーします。(コードスニペットを実行し、ページ全体のリンクをクリックして、テストする場合はdivのサイズが変更されているというアラートをトリガーします。

これが setIntervalが100ミリ秒私のPCはCPUの過度の空腹を検出しなかったと言ってもいいでしょう。(テスト時に、CPUの0.1%がChromeで開かれたすべてのタブの合計として使用されました。)しかし、これもまた1つのdivに対するものであり、大量の要素に対してこれを実行したい場合は、CPUを非常に消費する可能性があります。

とにかく、クリックイベントを使用して、div-resize スニッフィングを停止することができます。

var width = 0; 
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized div');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
</div>

フィドルもチェックできます

更新

var width = 0; 
function myInterval() {
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
return interval;
}
var interval = myInterval();
document.getElementById("clickMe").addEventListener( "click" , function() {
if(typeof interval!=="undefined") {
clearInterval(interval);
alert("stopped div-resize sniffing");
}
});
document.getElementById("clickMeToo").addEventListener( "click" , function() {
myInterval();
alert("started div-resize sniffing");
});
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" id="clickMe" />
        <input type="button" value="button 2" id="clickMeToo" />
        <input type="button" value="button 3" />
</div>

更新されたフィドル


2

これはトップアンサーのコピーとほぼ同じですが、リンクではなく、重要なコードの一部にすぎず、IMOがより読みやすく、理解しやすいように変換されています。他のいくつかの小さな変更には、cloneNode()の使用と、htmlをjs文字列に入れないことが含まれます。小さなものですが、これをそのままコピーして貼り付けることができます。

それが機能する方法は、2つの目に見えないdivを監視している要素を埋め、次にそれぞれにトリガーを配置し、サイズが変更された場合にスクロールの変更をトリガーするようにスクロール位置を設定することです。

すべての実際のクレジットはMarc Jに支払われますが、関連するコードを探しているだけの場合は、次のようになります。

    window.El = {}

    El.resizeSensorNode = undefined;
    El.initResizeNode = function() {
        var fillParent = "display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;";
        var triggerStyle = "position: absolute; left: 0; top: 0; transition: 0s;";

        var resizeSensor = El.resizeSensorNode = document.createElement("resizeSensor");
        resizeSensor.style = fillParent;

        var expandSensor = document.createElement("div");
        expandSensor.style = fillParent;
        resizeSensor.appendChild(expandSensor);

        var trigger = document.createElement("div");
        trigger.style = triggerStyle;
        expandSensor.appendChild(trigger);

        var shrinkSensor = expandSensor.cloneNode(true);
        shrinkSensor.firstChild.style = triggerStyle + " width: 200%; height: 200%";
        resizeSensor.appendChild(shrinkSensor);
    }


    El.onSizeChange = function(domNode, fn) {
        if (!domNode) return;
        if (domNode.resizeListeners) {
            domNode.resizeListeners.push(fn);
            return;
        }

        domNode.resizeListeners = [];
        domNode.resizeListeners.push(fn);

        if(El.resizeSensorNode == undefined)
            El.initResizeNode();

        domNode.resizeSensor = El.resizeSensorNode.cloneNode(true);
        domNode.appendChild(domNode.resizeSensor);

        var expand = domNode.resizeSensor.firstChild;
        var expandTrigger = expand.firstChild;
        var shrink = domNode.resizeSensor.childNodes[1];

        var reset = function() {
            expandTrigger.style.width = '100000px';
            expandTrigger.style.height = '100000px';

            expand.scrollLeft = 100000;
            expand.scrollTop = 100000;

            shrink.scrollLeft = 100000;
            shrink.scrollTop = 100000;
        };

        reset();

        var hasChanged, frameRequest, newWidth, newHeight;
        var lastWidth = domNode.offsetWidth;
        var lastHeight = domNode.offsetHeight;


        var onResized = function() {
            frameRequest = undefined;

            if (!hasChanged) return;

            lastWidth = newWidth;
            lastHeight = newHeight;

            var listeners = domNode.resizeListeners;
            for(var i = 0; listeners && i < listeners.length; i++) 
                listeners[i]();
        };

        var onScroll = function() {
            newWidth = domNode.offsetWidth;
            newHeight = domNode.offsetHeight;
            hasChanged = newWidth != lastWidth || newHeight != lastHeight;

            if (hasChanged && !frameRequest) {
                frameRequest = requestAnimationFrame(onResized);
            }

            reset();
        };


        expand.addEventListener("scroll", onScroll);
        shrink.addEventListener("scroll", onScroll);
    }

1

純粋なJavascriptソリューションですが、cssサイズ変更ボタンで要素のサイズが変更された場合にのみ機能します

  1. 要素のサイズをoffsetWidthおよびoffsetHeightで保存します。
  2. この要素にonclickイベントリスナーを追加します。
  3. トリガされたとき、海流を比較offsetWidthし、offsetHeight記憶された値と、異なる場合、あなたがやりたいことと、これらの値を更新します。

1

これは、@ nkronによるソリューションの簡略化されたバージョンで、単一の要素に適用できます(@nkronの回答の要素の配列の代わりに、私が必要としなかった複雑さ)。

function onResizeElem(element, callback) {    
  // Save the element we are watching
  onResizeElem.watchedElementData = {
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  };

  onResizeElem.checkForChanges = function() {
    const data = onResizeElem.watchedElementData;
    if (data.element.offsetWidth !== data.offsetWidth || data.element.offsetHeight !== data.offsetHeight) {
      data.offsetWidth = data.element.offsetWidth;
      data.offsetHeight = data.element.offsetHeight;
      data.callback();
    }
  };

  // Listen to the window resize event
  window.addEventListener('resize', onResizeElem.checkForChanges);

  // Listen to the element being checked for width and height changes
  onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
  onResizeElem.observer.observe(document.body, {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  });
}

イベントリスナーとオブザーバーは、次の方法で削除できます。

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();

0
jQuery(document).ready( function($) {

function resizeMapDIVs() {

// check the parent value...

var size = $('#map').parent().width();



if( $size < 640 ) {

//  ...and decrease...

} else {

//  ..or increase  as necessary

}

}

resizeMapDIVs();

$(window).resize(resizeMapDIVs);

});

0

Bharat Patilの回答を使用すると、最大のスタックエラーを防ぐためにバインドコールバック内でfalseを返すだけです。以下の例を参照してください。

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});

0

これは本当に古い質問ですが、私はこれに対する私の解決策を投稿すると思いました。

ResizeSensor誰もがかなり気になっていたので使ってみました。しかし実装した後、要素クエリの内部では問題の要素に位置relativeまたはabsolute適用する要素が必要であることを認識しましたが、これは私の状況では機能しませんでした。

私はこれをintervalストレートsetTimeoutまたはrequestAnimationFrame以前のような実装の代わりにRxjsで処理することになりました。

インターバルの監視可能なフレーバーの良いところは、ストリームを変更できることですが、他の監視可能なオブジェクトは処理できます。私にとっては、基本的な実装で十分でしたが、気が狂って、あらゆる種類のマージなどを行うことができました。

以下の例では、内側(緑)のdivの幅の変化を追跡しています。幅は50%に設定されていますが、最大幅は200pxです。スライダーをドラッグすると、ラッパー(灰色)divの幅に影響します。内側のdivの幅が変更されたときにのみオブザーバブルが発生することがわかります。これは、外側のdivの幅が400pxより小さい場合にのみ発生します。

const { interval } = rxjs;
const { distinctUntilChanged, map, filter } = rxjs.operators;


const wrapper = document.getElementById('my-wrapper');
const input = document.getElementById('width-input');




function subscribeToResize() {
  const timer = interval(100);
  const myDiv = document.getElementById('my-div');
  const widthElement = document.getElementById('width');
  const isMax = document.getElementById('is-max');
  
  /*
    NOTE: This is the important bit here 
  */
  timer
    .pipe(
      map(() => myDiv ? Math.round(myDiv.getBoundingClientRect().width) : 0),
      distinctUntilChanged(),
      // adding a takeUntil(), here as well would allow cleanup when the component is destroyed
    )
      .subscribe((width) => {        
        widthElement.innerHTML = width;
        isMax.innerHTML = width === 200 ? 'Max width' : '50% width';

      });
}

function defineRange() {
  input.min = 200;
  input.max = window.innerWidth;
  input.step = 10;
  input.value = input.max - 50;
}

function bindInputToWrapper() {
  input.addEventListener('input', (event) => {
    wrapper.style.width = `${event.target.value}px`;
  });
}

defineRange();
subscribeToResize();
bindInputToWrapper();
.inner {
  width: 50%;
  max-width: 200px;
}




/* Aesthetic styles only */

.inner {
  background: #16a085;
}

.wrapper {
  background: #ecf0f1;
  color: white;
  margin-top: 24px;
}

.content {
  padding: 12px;
}

body {
  
  font-family: sans-serif;
  font-weight: bold;
}
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

<h1>Resize Browser width</h1>

<label for="width-input">Adjust the width of the wrapper element</label>
<div>
  <input type="range" id="width-input">
</div>

<div id="my-wrapper" class="wrapper">
  <div id="my-div" class="inner">
    <div class="content">
      Width: <span id="width"></span>px
      <div id="is-max"></div>  
    </div>
  </div>
</div>


-1

Window.onResize仕様にのみ存在しますが、DIV内でIFrame新しいWindowオブジェクトを生成するためにいつでも利用できます。

この回答を確認してください。新しい小さなjqueryプラグインが追加されました。これは移植可能で使いやすいものです。いつでもソースコードをチェックして、それがどのように行われるかを確認できます。

<!-- (1) include plugin script in a page -->
<script src="/src/jquery-element-onresize.js"></script>

// (2) use the detectResizing plugin to monitor changes to the element's size:
$monitoredElement.detectResizing({ onResize: monitoredElement_onResize });

// (3) write a function to react on changes:
function monitoredElement_onResize() {    
    // logic here...
}

サイズ変更可能なdivがある場合、これは非常に非効率的なソリューションです。
suricactus 2015年

-1

できないと思ったのですが、考えたところ、style = "resize:both;"を使用してdivのサイズを手動で変更できます。そのためには、クリックする必要があるので、要素の高さと幅をチェックするonclick関数を追加し、機能しました。純粋なjavascriptが5行しかない場合(さらに短くなる可能性がありますhttp://codepen.io/anon/pen/eNyyVN

<div id="box" style="
                height:200px; 
                width:640px;
                background-color:#FF0066;
                resize: both;
                overflow: auto;" 
                onclick="myFunction()">
    <p id="sizeTXT" style="
                font-size: 50px;">
       WxH
    </p>
    </div>

<p>This my example demonstrates how to run a resize check on click for resizable div.</p>

<p>Try to resize the box.</p>


<script>
function myFunction() {
var boxheight = document.getElementById('box').offsetHeight;
var boxhwidth = document.getElementById('box').offsetWidth;
var txt = boxhwidth +"x"+boxheight;
document.getElementById("sizeTXT").innerHTML = txt;
}
</script>

2
これは、質問の要件の一部ではないクリックイベントが発生したときにのみ計算されます。
Rob Evans
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.