Événement de redimensionnement de la fenêtre JavaScript

618

Comment puis-je me connecter à un événement de redimensionnement de la fenêtre du navigateur?

Il existe un moyen jQuery d'écouter les événements de redimensionnement mais je préférerais ne pas l'intégrer dans mon projet pour cette seule exigence.

Compte mort
la source
8
Merci tout le monde. Je ne me soucie pas d'IE, je pensais plus au redimensionnement pour l'opéra sur un téléphone mobile.
Compte mort

Réponses:

640

jQuery enveloppe simplement l' resizeévénement DOM standard , par exemple.

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

jQuery peut faire un certain travail pour s'assurer que l'événement de redimensionnement est déclenché de manière cohérente dans tous les navigateurs, mais je ne suis pas sûr si l'un des navigateurs diffère, mais je vous encourage à tester dans Firefox, Safari et IE.

olliej
la source
226
Un problème potentiel avec cette méthode est que vous remplacez l'événement et que vous ne pouvez donc pas attacher plusieurs actions à un événement. Le combo addEventListener / attachEvent est la meilleure façon de rendre votre jeu javascript convivial avec tout autre script qui pourrait être en cours d'exécution sur la page.
MyItchyChin
4
var onresize = window.onresize; window.onresize = function (event) {if (typeof onresize === 'function') onresize (); / ** ... * /}
SubOne
230
window.addEventListener('resize', function(){}, true);
WebWanderer
16
@SubOne un parfait exemple de la façon dont on ne devrait jamais le faire.
Eugene Pankov
28
ECMAScript 6 : window.onresize = () => { /* code */ };ou mieux:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman
561

Tout d'abord, je sais que la addEventListenerméthode a été mentionnée dans les commentaires ci-dessus, mais je n'ai vu aucun code. Puisque c'est l'approche préférée, la voici:

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

Voici un exemple de travail .

Jondlm
la source
63
C'est la réponse la plus simple.
jacoviza
7
Cela semble être la meilleure réponse car vous n'écrasez pas l'événement window.onresize :-)
James Harrington
27
De nombreuses personnes ajoutent des écouteurs d'événements anonymes comme vous le faites dans cet exemple, mais ce n'est pas vraiment une bonne pratique, car cette approche rend impossible la suppression de ces écouteurs plus tard. Auparavant, cela ne posait aucun problème car les pages Web étaient de courte durée de toute façon, mais à l'époque d'AJAX et des RIA et SPA, cela devient un. Nous avons besoin d'un moyen de gérer le cycle de vie des écouteurs d'événements. Ainsi, il serait préférable de factoriser la fonction d'écoute dans une fonction distincte afin qu'elle puisse être supprimée plus tard avec removeEventListener.
Stijn de Witt
6
pourquoi ne peut pas répondre à tout le monde comme cela sans toutes les peluches
quemeful
2
Je pense qu'il y a du vrai dans les réponses de Stijn de Witt et de quemeful ici. Parfois, vous vous souciez de supprimer les écouteurs d'événements, mais dans le cas contraire, ajouter tout ce code supplémentaire comme dans l'exemple ci-dessus n'est pas nécessaire et peut à la fois gonfler et réduire la lisibilité. À mon avis, si vous n'envisagez pas de raison de supprimer l'auditeur, cette approche est la meilleure solution. Vous pouvez toujours le réécrire plus tard si nécessaire. D'après mon expérience, ces besoins ne se posent que dans des situations spécifiques.
cazort
524

Ne remplacez jamais la fonction window.onresize.

Au lieu de cela, créez une fonction pour ajouter un écouteur d'événements à l'objet ou à l'élément. Cela vérifie et empêche les écouteurs de fonctionner, puis remplace la fonction de l'objet en dernier recours. Il s'agit de la méthode préférée utilisée dans les bibliothèques telles que jQuery.

object: l'élément ou l'objet fenêtre
type: redimensionner, faire défiler (type d'événement)
callback: la référence de la fonction

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;
    }
};

Ensuite, l'utilisation est comme ceci:

addEvent(window, "resize", function_reference);

ou avec une fonction anonyme:

addEvent(window, "resize", function(event) {
  console.log('resized');
});
Alex V
la source
100
Cela aurait dû être la réponse acceptée. Remplacer une taille n'est qu'une mauvaise pratique.
Tiberiu-Ionuț Stan
8
hah, qu'est-ce qui se passe avec tous les contrôles nuls supplémentaires? essayer de travailler dans IE 4.5 ou quelque chose?
FlavorScape
1
Et vous vous demandez comment appeler cette fonction pour recevoir des événements de redimensionnement de fenêtre? Voici comment: addEvent (window, "resize", function_reference); :)
oabarca
6
Notez qu'à partir d'IE 11, attachEventn'est plus pris en charge. La voie privilégiée pour l'avenir est addEventListener.
Luke
6
Soyez prudent avec elem == undefined. Il est possible (bien que peu probable) que "non défini" soit défini localement comme autre chose. stackoverflow.com/questions/8175673/…
Luke
32

L'événement de redimensionnement ne doit jamais être utilisé directement car il est déclenché en continu pendant que nous redimensionnons.

Utilisez une fonction anti-rebond pour atténuer les appels en excès.

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

Voici un rebounce commun flottant autour du net, mais recherchez des plus avancés comme featuerd dans 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);
    };
};

Cela peut être utilisé comme ça ...

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

Il ne se déclenchera jamais plus d'une fois tous les 200 ms.

Pour les changements d'orientation mobile, utilisez:

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

Voici une petite bibliothèque que j'ai constituée pour prendre soin de cela proprement.

face avant
la source
J'apprécie les informations sur: debounce (cela semble maintenant un concept / fonction inestimable même si j'ai précédemment résisté à l'utilisation des délais d'attente de cette manière), lodash (bien que je ne sois personnellement pas convaincu) et la résolution de l'ambiguïté sur l'opportunité d'utiliser addEvent comme solution de repli to addEventListener (uniquement parce que les réponses plus anciennes ne répondent pas vraiment explicitement aux commentaires à ce sujet)
wunth
5
Pour info puisque vous utilisez la notation func de la flèche ES6, la fonction interne doit avoir (...arguments) => {...}(ou ...argspour moins de confusion) car la argumentsvariable n'est plus disponible dans sa portée.
coderatchet
Je suis parfaitement conscient que cet extrait n'est pas mon code, c'est juste à titre d'exemple.
frontsideup
Excellente réponse, les problèmes de perf avec redimensionnement doivent être résolus! La anti-rebond est une option, une autre est une limitation simple (ce qui pourrait être la voie à suivre si vous avez besoin de redimensionner votre interface utilisateur en "étapes"). Voir bencentra.com/code/2015/02/27/optimizing-window-resize.html pour des exemples
Robin Métral
24

Solution pour 2018+:

Vous devez utiliser ResizeObserver . Il s'agit d'une solution native du navigateur qui a de bien meilleures performances que d'utiliser l' resizeévénement. De plus, il supporte non seulement l'événement sur le documentmais aussi sur l'arbitraire 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);

Actuellement, Firefox, Chrome et Safari le prennent en charge . Pour les autres navigateurs (et les anciens), vous devez utiliser un polyfill .

str
la source
Toujours la meilleure réponse en 2020 imo
Jesse Reza Khorasanee
16

Je crois que la réponse correcte a déjà été fournie par @Alex V, mais la réponse nécessite une certaine modernisation car elle a plus de cinq ans maintenant.

Il y a deux problèmes principaux:

  1. Ne jamais utiliser objectcomme nom de paramètre. C'est un mot réservé. Cela étant dit, la fonction fournie par @Alex V ne fonctionnera pas strict mode.

  2. La addEventfonction fournie par @Alex V ne renvoie pas le event objectsi la addEventListenerméthode est utilisée. Un autre paramètre doit être ajouté à la addEventfonction pour permettre cela.

REMARQUE: le nouveau paramètre to addEventa été rendu facultatif afin que la migration vers cette nouvelle version de fonction n'interrompe aucun appel précédent à cette fonction. Toutes les utilisations héritées seront prises en charge.

Voici la addEventfonction mise à jour avec ces modifications:

/*
    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;
};

Un exemple d'appel à la nouvelle addEventfonction:

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);
WebWanderer
la source
Je dirais que attachEvent n'est plus pertinent en 2017.
Vlad Nicula
@VladNicula Je serais d'accord, mais cette réponse a deux ans.
WebWanderer
12

Merci d'avoir référencé mon article de blog sur http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html .

Bien que vous puissiez simplement vous connecter à l'événement de redimensionnement de fenêtre standard, vous constaterez que dans IE, l'événement est déclenché une fois pour chaque mouvement X et une fois pour chaque mouvement de l'axe Y, ce qui entraîne le déclenchement d'une tonne d'événements pouvant avoir des performances impact sur votre site si le rendu est une tâche intensive.

Ma méthode implique un court délai d'attente qui est annulé lors d'événements ultérieurs afin que l'événement ne se propage pas à votre code jusqu'à ce que l'utilisateur ait fini de redimensionner la fenêtre.

Steven
la source
7
window.onresize = function() {
    // your code
};
saravanakumar
la source
22
Comme le disent de nombreux commentaires ci-dessus, il est préférable de ne pas écraser la fonction onresize; ajoutez plutôt un nouvel événement. Voir la réponse de Jondlm.
Luke
6

Le billet de blog suivant peut vous être utile: Correction de l'événement de redimensionnement de la fenêtre dans IE

Il fournit ce code:

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);
}
lakshmanaraj
la source
6
Celui-ci s'applique uniquement aux applications ASP.NET
Evgeny Gorb
2

Les solutions déjà mentionnées ci-dessus fonctionneront si tout ce que vous voulez faire est de redimensionner la fenêtre et la fenêtre uniquement. Toutefois, si vous souhaitez que le redimensionnement soit propagé aux éléments enfants, vous devrez propager l'événement vous-même. Voici un exemple de code pour le faire:

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

Notez qu'un élément enfant peut appeler

 event.preventDefault();

sur l'objet événement transmis comme premier Arg de l'événement resize. Par exemple:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});
rysama
la source
1
<script language="javascript">
    window.onresize = function() {
    document.getElementById('ctl00_ContentPlaceHolder1_Accordion1').style.height = '100%';
} 

</script>
Rob Herring
la source
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_];
        }
    }
}
L'INCROYABLE
la source