div要素のサイズを変更する


80

jQueryにはresize()-イベントがありますが、ウィンドウでのみ機能します。

jQuery(window).resize(function() { /* What ever */ });

これは問題なく動作します!しかし、イベントをdiv要素に追加したい場合、それは機能しません。

例えば

jQuery('div').resize(function() { /* What ever */ });

div要素のサイズが変更されたときにコールバックを開始したい。サイズ変更可能なイベントを開始したくありません。div要素のサイズが変更されたかどうかを確認するためのイベントだけです。

これを行うための解決策はありますか?


2
サイズ変更イベントは、ウィンドウオブジェクト(およびiframeかもしれません)でのみ発生します。
BiAiB 2012


これは役立つかもしれません:resizeObserver。 developer.mozilla.org/en-US/docs/Web/API/ResizeObserver。クローム64でサポートされている、Firefoxの69 ...
船長はピュージェット

回答:


35

DIVresizeイベントを発生させないため、コーディングした内容を正確に実行することはできませんが、DOMプロパティの監視を調べることはできます。

サイズ変更可能なもののようなものを実際に使用していて、それがdivのサイズを変更する唯一の方法である場合、サイズ変更プラグインはおそらく独自のコールバックを実装します。


$(window).trigger( "resize");を使用してウィンドウサイズ変更イベントをトリガーできます。
ローラン

32

要素の幅が変更されたときのトリガーにのみ関心があったので(高さは気にしません)、非表示のiframe要素を使用してそれを正確に行うjqueryイベントを作成しました。

$.event.special.widthChanged = {
  remove: function() {
      $(this).children('iframe.width-changed').remove();
  },
  add: function () {
      var elm = $(this);
      var iframe = elm.children('iframe.width-changed');
      if (!iframe.length) {
          iframe = $('<iframe/>').addClass('width-changed').prependTo(this);
      }
      var oldWidth = elm.width();
      function elmResized() {
          var width = elm.width();
          if (oldWidth != width) {
              elm.trigger('widthChanged', [width, oldWidth]);
              oldWidth = width;
          }
      }

      var timer = 0;
      var ielm = iframe[0];
      (ielm.contentWindow || ielm).onresize = function() {
          clearTimeout(timer);
          timer = setTimeout(elmResized, 20);
      };
  }
}

次のCSSが必要です。

iframe.width-changed {
    width: 100%;
    display: block;
    border: 0;
    height: 0;
    margin: 0;
}

ここで実際の動作を確認できますwidthChangedフィドル


これが正解です。イベントをiframeのウィンドウに添付することは、間隔よりもはるかに簡単です。
ケビンビール2014年

1
これは完璧です!私はスタイルシートを動的に追加することで完全にjsベースにしました: var ss = document.createElement('style'); ss.type = "text/css"; ss.innerHTML = "iframe.width-changed {width: 100%;display: block;border: 0;height: 0;margin: 0;}"; document.body.appendChild(ss);
sroskelley 2016

これは純粋な天才です。
トーマス

私はそれを使用しようとしていますが、私は疑問に思います:タイマーとsetTimeoutの役割は何ですか?ユーザーが要素のサイズを変更したときに検出されるサイズが多すぎるのを防ぐための「デバウンス」/スロットルのようなものですか?
マシュー

はい、「widthChanged」トリガーを何度も呼び出さないようにするためです
PanosTheof18年

22
// this is a Jquery plugin function that fires an event when the size of an element is changed
// usage: $().sizeChanged(function(){})

(function ($) {

$.fn.sizeChanged = function (handleFunction) {
    var element = this;
    var lastWidth = element.width();
    var lastHeight = element.height();

    setInterval(function () {
        if (lastWidth === element.width()&&lastHeight === element.height())
            return;
        if (typeof (handleFunction) == 'function') {
            handleFunction({ width: lastWidth, height: lastHeight },
                           { width: element.width(), height: element.height() });
            lastWidth = element.width();
            lastHeight = element.height();
        }
    }, 100);


    return element;
};

}(jQuery));

7

jqueryプラグインjquery.resizeを作成しました。サポートされている場合はresizeObserverを使用するか、marcj / css-element-queriesスクロールイベントに基づくソリューションで、setTimeout / setIntervalは使用しません。

あなたはただ使う

 jQuery('div').on('resize', function() { /* What ever */ });

またはリサイザープラグインとして

jQuery('div').resizer(function() { /* What ever */ });

これをjQueryターミナル用に作成し、別々のリポジトリとnpmパッケージに抽出しましたが、要素がiframe内にある場合にサイズ変更に問題があったため、その間に非表示のiframeに切り替えました。それに応じてプラグインを更新する場合があります。jQueryターミナルのソースコードiframeベースのリサイザープラグインを見ることができます。

編集:新しいバージョンはiframeを使用し、ページがiframe内にあるときに以前のソリューションが機能していなかったため、ウィンドウオブジェクトのサイズを変更します。

EDIT2:フォールバックはiframeを使用するため、フォームコントロールや画像では使用できないため、ラッパー要素に追加する必要があります。

EDIT3 ::ミューテーションオブザーバーを使用し(resizeObserverがサポートされていない場合)、IEでも機能するresizeObserverポリフィルを使用したより良いソリューションがあります。TypeScriptタイピングもあります。


それは素晴らしいアイデアでした。本当によくできました。
マルコ・ルッザーラ

6

これはどうですか:

divH = divW = 0;
jQuery(document).ready(function(){
    divW = jQuery("div").width();
    divH = jQuery("div").height();
});
function checkResize(){
    var w = jQuery("div").width();
    var h = jQuery("div").height();
    if (w != divW || h != divH) {
        /*what ever*/
        divH = h;
        divW = w;
    }
}
jQuery(window).resize(checkResize);
var timer = setInterval(checkResize, 1000);

ところで、divにIDを追加し、$( "div")を$( "#yourid")に変更することをお勧めします。これは高速になり、後で他のdivを追加しても壊れません。


もちろん、これは単なる例でした。もちろん、IDとクラスを使用して要素を選択します。私はあなたのアイデアが好きです-私はそれがうまくいくと思います!どうもありがとう。数分で試して、フィードバックを提供します。
TJR 2012

これは、ウィンドウのresizeイベントが発生するたびに、サイズの変更についてDIVを監視します。ウィンドウのサイズ変更がすぐに行われずにdivのサイズが変更されることは非常に考えられます/* what ever */。その場合、パーツは評価されません。
David Hedlund 2012

正しい!そして、これが私のプロジェクトの問題です。div要素は、css属性Overflow:hiddenを持つ外部ラッパーにあるため、ウィンドウのサイズは変更されません。しかし、他の方法では、例は正常に機能します-私はそれをテストしました。
TJR 2012

@Timo:$(window).resizeたとえば、右下隅をドラッグして、ブラウザウィンドウのサイズを物理的に変更する動作をリッスンします。このイベントをトリガーするかどうかにoverflow:hiddenかかわらず、DOMイベントはこれまでありません。この答えはあなたの問題に対処していません。このコードをタイマーで実行する方が、トリガーされない可能性が高いランダムなイベントリスナーにアタッチするよりも理にかなっています。DOMプロパティの監視を使用してタイマーにフォールバックできる(またはdivサイズが変更される可能性のある場所でイベントを手動で発生させる)ことができればさらに良いでしょう。
David Hedlund 2012

setIntervalのコードを追加しました。微調整する必要があります。'1000msは長すぎる可能性がありますが、数値が小さすぎるとCPUが簡単に停止する可能性があります。これ以上聞く必要がないことがわかっている場合は、clearInterval(timer)を呼び出します。
Gavriel 2012

5

今年リリースされた基本的なJavaScriptとjQueryの両方に、非常に優れた、使いやすく、軽量な(検出にネイティブブラウザイベントを使用する)プラグインがあります。それは完璧に機能します:

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


1
常にポーリングするわけではないとおっしゃいました
Muhammad

1
興味深い:参照されているGitHubプロジェクトは、このブログ投稿に触発されました:backalleycoder.com/2013/03/18/…しかし、投稿のコードは後で大幅に変更されましたが、GitHubプロジェクトは古いアプローチを使用しているようです。したがって、何を使用するかを決める前に、両方を確認する価値があります。
CF


0

グーグルマップの統合のために、私はdivのサイズが変更されたことを検出する方法を探していました。グーグルマップは、適切にレンダリングするために、幅や高さなどの適切な寸法を常に必要とするためです。

私が思いついた解決策は、イベントの委任、私の場合はタブクリックです。もちろん、これはウィンドウのサイズ変更である可能性がありますが、考え方は同じです。

if (parent.is(':visible')) {
    w = parent.outerWidth(false);
    h = w * mapRatio /*9/16*/;
    this.map.css({ width: w, height: h });
} else {
    this.map.closest('.tab').one('click', function() {
        this.activate();
    }.bind(this));
}

this.mapこの場合は私のマップdivです。私の親はロード時に表示されないため、計算された幅と高さは0であるか、一致しません。を使用.bind(this)することで、スクリプトの実行(this.activate)をイベント(click)に委任できます。

これで、同じことがサイズ変更イベントにも当てはまると確信しています。

$(window).one('resize', function() {
    this.div.css({ /*whatever*/ });
}.bind(this));

それが誰にでも役立つことを願っています!


0

この関数を試してみてください(divだけでなく機能する場合もあります):

function resized(elem, func = function(){}, args = []){
    elem = jQuery(elem);
    func = func.bind(elem);
    var h = -1, w = -1;
    setInterval(function(){
        if (elem.height() != h || elem.width() != w){
            h = elem.height();
            w = elem.width();
            func.apply(null, args);
        }
    }, 100);
}

このように使えます

resized(/*element*/ '.advs-columns-main > div > div', /*callback*/ function(a){
    console.log(a);
    console.log(this); //for accessing the jQuery element you passed
}, /*callback arguments in array*/ ['I\'m the first arg named "a"!']);

更新: よりプログレッシブなウォッチャーを使用することもできます(DOM要素だけでなく、任意のオブジェクトに対して機能します):

function changed(elem, propsToBeChanged, func = function(){}, args = [], interval = 100){
        func = func.bind(elem);
        var currentVal = {call: {}, std: {}};
        $.each(propsToBeChanged, (property, needCall)=>{
            needCall = needCall ? 'call' : 'std';
            currentVal[needCall][property] = new Boolean(); // is a minimal and unique value, its equivalent comparsion with each other will always return false
        });
        setInterval(function(){
            $.each(propsToBeChanged, (property, needCall)=>{
                try{
                    var currVal = needCall ? elem[property]() : elem[property];
                } catch (e){ // elem[property] is not a function anymore
                    var currVal = elem[property];
                    needCall = false;
                    propsToBeChanged[property] = false;
                }
                needCall = needCall ? 'call' : 'std';
                if (currVal !== currentVal[needCall][property]){
                    currentVal[needCall][property] = currVal;
                    func.apply(null, args);
                }
            });
        }, interval);
    }

やってみなよ:

var b = '2',
    a = {foo: 'bar', ext: ()=>{return b}};
changed(a, {
// prop name || do eval like a function?
    foo:        false,
    ext:        true
}, ()=>{console.log('changed')})

b、a.foo、またはa.extを直接変更するたびに、「変更された」ログが記録されます。


setIntervalサイズ変更を試み続けるため、かなり高額になる可能性があります
トン

@ton:あなたは完全に正しくないと思います。これは、サイズ変更中に要素のサイズを変更しようとした場合にのみ発生します。:/または、パフォーマンスが心配ですか?最新のブラウザでは、「重い」サイトでも完全に機能します
KaMeHb 2017

あなたは、単純なを追加します場合はconsole.log直前に$.each、あなたはそれがすべての印刷を参照してくださいよ100msあなたが設定したとして、interval
トン

@ton:あなたは私を間違って理解しました。私はどのようにsetInterval機能するかよく知っています。これは「生きている」電子メールのようなもので、常にサーバーにpingを送信します。私はそれを知っている。そして何?パフォーマンス?上記の私のコメントを読んでください。他に何か心配ですか?私を書いてください、私の友人。
KaMeHb 2017

0

画面サイズに応じて、テキストまたはコンテンツまたは属性を変更できます。HTML:

<p class="change">Frequently Asked Questions (FAQ)</p>
<p class="change">Frequently Asked Questions </p>

Javascript:

<script>
const changeText = document.querySelector('.change');
function resize() {
  if((window.innerWidth<500)&&(changeText.textContent="Frequently Asked Questions (FAQ)")){
    changeText.textContent="FAQ";
  } else {
    changeText.textContent="Frequently Asked Questions (FAQ)";
  }
}
window.onresize = resize;
</script>

-2

div自体のサイズを変更したいだけの場合は、cssスタイルで指定する必要があります。あなたは追加する必要がオーバーフローし、プロパティのサイズを変更します

以下は私のコードスニペットです

#div1 {
        width: 90%;
        height: 350px;
        padding: 10px;
        border: 1px solid #aaaaaa;
        overflow: auto;
        resize: both;
    }

<div id="div1">

</div>

この回答は元の投稿には適用されません。ここでの大まかな議論は、要素のサイズを設定するのではなく、要素のサイズの変更をリッスンすること(および後でアクションを実行すること)についてです。
MarsAndBack
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.