JavaScriptウィンドウサイズ変更イベント


618

ブラウザウィンドウのサイズ変更イベントにフックするにはどうすればよいですか?

サイズ変更イベントをリッスンするjQueryの方法はありますが、この1つの要件のためだけに、プロジェクトにjQueryを組み込まないようにします。


8
みんな、ありがとう。IEは気にしません。携帯電話でのオペラのサイズ変更についてもっと考えていました。
デッドアカウント

回答:


640

jQueryは標準のresizeDOMイベントをラップするだけです。

window.onresize = function(event) {
    ...
};

jQuery 、すべてのブラウザーで一貫してresizeイベントが発生するようにいくつかの作業を行う場合がありますが、ブラウザーのいずれかが異なるかどうかはわかりませんが、Firefox、Safari、IEでテストすることをお勧めします。


226
このメソッドの1つの潜在的な問題は、イベントをオーバーライドするため、イベントに複数のアクションをアタッチできないことです。addEventListener / attachEventコンボは、ページで実行されている可能性のある他のスクリプトとJavaScriptを親しみやすくするための最良の方法です。
MyItchyChin 2011年

4
var onresize = window.onresize; window.onresize = function(event){if(typeof onresize === 'function')onresize(); / ** ... * /}
SubOne 2012

230
window.addEventListener('resize', function(){}, true);
WebWanderer 2014年

16
@SubOneは、決して実行してはならない方法の完全な例です。
Eugene Pankov 2016

28
ECMAScript 6window.onresize = () => { /* code */ };以上:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman 2017

561

まず、addEventListener上記のコメントでメソッドが言及されていることは知っていますが、コードは表示されませんでした。これが推奨されるアプローチなので、ここに示します。

window.addEventListener('resize', function(event){
  // do stuff here
});

こちらが実際のサンプルです。


63
これが最も簡単な答えです。
jacoviza 14

7
あなたがwindow.onresizeイベントを上書きしないので、最高の答えのように聞こえます:-)
James Harrington

27
この例のように、多くの人が匿名イベントリスナーを追加しますが、この方法では後でこれらのリスナーを削除することが不可能になるため、あまり良い方法ではありません。とにかくWebページは短命だったのでこれは問題ではありませんでしたが、AJAXとRIAとSPAの今日の時代には、1つになりつつあります。イベントリスナーのライフサイクルを管理する方法が必要です。したがって、後でで削除できるように、リスナー関数を別の関数に分解することをお勧めしremoveEventListenerます。
Stijn de Witt 2016

6
なぜ、すべての綿毛なしでこのようなことはできない、誰も答え
quemeful

2
ここでは、Stijn de Wittとquemefulの両方の答えに真実があると思います。場合によっては、イベントリスナーの削除に関心がありますが、削除しない場合は、上記の例のような追加のコードをすべて追加する必要はなく、肥大化と読みやすさの両方を損なう可能性があります。私の意見では、リスナーを削除する必要がある理由を想定していない場合、このアプローチが最善の解決策です。必要に応じて、後でいつでも書き換えることができます。私の経験では、これらのニーズは特定の状況でのみ発生します。
cazort

524

window.onresize関数をオーバーライドしないでください。

代わりに、オブジェクトまたは要素にイベントリスナーを追加する関数を作成します。これは、リスナーが機能しないことを確認し、その場合、最後の手段としてオブジェクトの機能をオーバーライドします。これは、jQueryなどのライブラリで使用される推奨メソッドです。

object:要素またはウィンドウオブジェクト
type:サイズ変更、スクロール(イベントタイプ)
callback:関数リファレンス

var addEvent = function(object, type, callback) {
    if (object == null || typeof(object) == 'undefined') return;
    if (object.addEventListener) {
        object.addEventListener(type, callback, false);
    } else if (object.attachEvent) {
        object.attachEvent("on" + type, callback);
    } else {
        object["on"+type] = callback;
    }
};

次に、このように使用します:

addEvent(window, "resize", function_reference);

または無名関数を使って:

addEvent(window, "resize", function(event) {
  console.log('resized');
});

100
これは受け入れられるべき答えでした。onresizeのオーバーライドは、単に悪い習慣です。
Tiberiu-Ionuț Stan

8
ああ、すべての余分なnullチェックとは何ですか?IE 4.5か何かで動作しようとしていますか?
FlavorScape 2012

1
また、この関数を呼び出してウィンドウサイズ変更イベントを受け取るにはどうすればよいでしょうか。方法は次のとおりです。addEvent(window、 "resize"、function_reference); :)
oabarca 2014

6
IE 11以降attachEventはサポートされなくなりました。将来の推奨方法はaddEventListenerです。
ルーク

6
に注意してくださいelem == undefined。「可能性は低いですが」「未定義」がローカルで別のものとして定義されている可能性があります。stackoverflow.com/questions/8175673/…–
ルーク、

32

resizeイベントは、サイズ変更時に継続的に発生するため、直接使用しないでください。

デバウンス機能を使用して、過剰な呼び出しを軽減します。

window.addEventListener('resize',debounce(handler, delay, immediate),false);

これはネット上に浮かぶ一般的なデバウンスですが、lodashの機能としてより高度なものを探します。

const debounce = (func, wait, immediate) => {
    var timeout;
    return () => {
        const context = this, args = arguments;
        const later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        const callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

これは次のように使用できます...

window.addEventListener('resize', debounce(() => console.log('hello'),
200, false), false);

200ミリ秒に1回以上発砲することはありません。

モバイルの向きを変更するには、次を使用します。

window.addEventListener('orientationchange', () => console.log('hello'), false);

これをきちんと処理するためにまとめた小さなライブラリを以下に示します。


私は情報に感謝します:デバウンス(以前はこの方法でタイムアウトを使用して抵抗していたにもかかわらず、今では非常に貴重な概念/機能のようです)、lodash(私は個人的には確信していません)、およびaddEventをフォールバックとして使用するかどうかのあいまいさを解決しますaddEventListenerへ(以前の回答ではこれに関するコメントに実際に明示的に対応していないためのみ)
wunth

5
参考までに、ES6の矢印関数表記を使用しているため、変数がスコープで使用できなくなったため、内部関数に(...arguments) => {...}(または...args混乱を減らすために)必要がありargumentsます。
coderatchet 2017

私は完全に承知しています。スニペットは私のコードではなく、単なる例です。
frontsideup

良い答えです。サイズ変更に関するパフォーマンスの問題に対処する必要があります。デバウンスはオプションであり、もう1つは単純なスロットルです(「ステップ」でUIのサイズを変更する必要がある場合は、この方法が適している場合があります)。例についてはbencentra.com/code/2015/02/27/optimizing-window-resize.htmlをご覧ください
RobinMétralOct

24

2018以降のソリューション:

ResizeObserverを使用する必要があります。これは、resizeイベントを使用するよりもはるかに優れたパフォーマンスを持つブラウザーネイティブのソリューションです。さらに、だけでなくdocument任意ののイベントもサポートしelementsます。

var ro = new ResizeObserver( entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;
    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

現在、Firefox、Chrome、Safariでサポートされています。他の(および古い)ブラウザーでは、ポリフィルを使用する必要があります。


それでも2020年のベストアンサーimo
Jesse Reza Khorasanee


16

正しい答えは@Alex Vによってすでに提供されていると私は確信していますが、答えは現在5年以上経過しているため、いくつかの近代化が必要です。

主な問題は2つあります。

  1. objectパラメータ名として使用しないでください。予約語です。そのため、@ Alex Vが提供する関数はで機能しませんstrict mode

  2. addEvent@Alex Vによって提供される機能は返さないevent object場合はaddEventListenerこの方法が使用されています。addEventこれを可能にするには、関数に別のパラメーターを追加する必要があります。

注:addEventこの新しい関数バージョンに移行しても、この関数への以前の呼び出しが中断されないように、新しいパラメーターto はオプションになっています。すべてのレガシー使用がサポートされます。

addEventこれらの変更で更新された関数は次のとおりです。

/*
    function: addEvent

    @param: obj         (Object)(Required)

        -   The object which you wish
            to attach your event to.

    @param: type        (String)(Required)

        -   The type of event you
            wish to establish.

    @param: callback    (Function)(Required)

        -   The method you wish
            to be called by your
            event listener.

    @param: eventReturn (Boolean)(Optional)

        -   Whether you want the
            event object returned
            to your callback method.
*/
var addEvent = function(obj, type, callback, eventReturn)
{
    if(obj == null || typeof obj === 'undefined')
        return;

    if(obj.addEventListener)
        obj.addEventListener(type, callback, eventReturn ? true : false);
    else if(obj.attachEvent)
        obj.attachEvent("on" + type, callback);
    else
        obj["on" + type] = callback;
};

新しいaddEvent関数の呼び出し例:

var watch = function(evt)
{
    /*
        Older browser versions may return evt.srcElement
        Newer browser versions should return evt.currentTarget
    */
    var dimensions = {
        height: (evt.srcElement || evt.currentTarget).innerHeight,
        width: (evt.srcElement || evt.currentTarget).innerWidth
    };
};

addEvent(window, 'resize', watch, true);

私はattachEventが2017年にはもはや適切であると主張しないだろう
ヴラドNicula

@VladNicula私は同意するでしょうが、この答えは2歳です。
WebWanderer 2017年

12

http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.htmlにある私のブログ投稿を参照していただきありがとうございます。

標準のウィンドウサイズ変更イベントに接続するだけでよいのですが、IEでは、Xごとに1回、Y軸の移動ごとに1回、イベントが発生します。その結果、大量のイベントが発生し、パフォーマンスが向上する場合がありますレンダリングが集中的なタスクである場合、サイトに影響を与えます。

私の方法は、ユーザーがウィンドウのサイズ変更を完了するまでイベントがコードにバブリングしないように、後続のイベントでキャンセルされる短いタイムアウトを含みます。


7
window.onresize = function() {
    // your code
};

22
上記のコメントの多くが言うように、onresize関数を上書きしないことが最善です。むしろ新しいイベントを追加します。Jondlmの回答を参照してください。
ルーク、

6

次のブログ投稿が役立つかもしれません:IEでのウィンドウサイズ変更イベントの修正

それはこのコードを提供します:

Sys.Application.add_load(function(sender, args) {
    $addHandler(window, 'resize', window_resize);
});

var resizeTimeoutId;

function window_resize(e) {
     window.clearTimeout(resizeTimeoutId);
     resizeTimeoutId = window.setTimeout('doResizeCode();', 10);
}

6
これはASP.NETアプリケーションにのみ適用されます
Evgeny Gorb '

2

上記の解決策は、ウィンドウとウィンドウのみのサイズを変更したい場合にのみ機能します。ただし、サイズ変更を子要素に伝達したい場合は、自分でイベントを伝達する必要があります。これを行うコードの例をいくつか示します。

window.addEventListener("resize", function () {
  var recResizeElement = function (root) {
    Array.prototype.forEach.call(root.childNodes, function (el) {

      var resizeEvent = document.createEvent("HTMLEvents");
      resizeEvent.initEvent("resize", false, true);
      var propagate = el.dispatchEvent(resizeEvent);

      if (propagate)
        recResizeElement(el);
    });
  };
  recResizeElement(document.body);
});

子要素が呼び出すことができることに注意してください

 event.preventDefault();

resizeイベントの最初のArgとして渡されるイベントオブジェクト。例えば:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});

1
<script language="javascript">
    window.onresize = function() {
    document.getElementById('ctl00_ContentPlaceHolder1_Accordion1').style.height = '100%';
} 

</script>

1
var EM = new events_managment();

EM.addEvent(window, 'resize', function(win,doc, event_){
    console.log('resized');
    //EM.removeEvent(win,doc, event_);
});

function events_managment(){
    this.events = {};
    this.addEvent = function(node, event_, func){
        if(node.addEventListener){
            if(event_ in this.events){
                node.addEventListener(event_, function(){
                    func(node, event_);
                    this.events[event_](win_doc, event_);
                }, true);
            }else{
                node.addEventListener(event_, function(){
                    func(node, event_);
                }, true);
            }
            this.events[event_] = func;
        }else if(node.attachEvent){

            var ie_event = 'on' + event_;
            if(ie_event in this.events){
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                    this.events[ie_event]();
                });
            }else{
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                });
            }
            this.events[ie_event] = func;
        }
    }
    this.removeEvent = function(node, event_){
        if(node.removeEventListener){
            node.removeEventListener(event_, this.events[event_], true);
            this.events[event_] = null;
            delete this.events[event_];
        }else if(node.detachEvent){
            node.detachEvent(event_, this.events[event_]);
            this.events[event_] = null;
            delete this.events[event_];
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.