Evento di ridimensionamento della finestra JavaScript


Risposte:


640

jQuery sta semplicemente avvolgendo l' resizeevento DOM standard , ad es.

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

jQuery potrebbe fare un po 'di lavoro per garantire che l'evento di ridimensionamento venga attivato costantemente in tutti i browser, ma non sono sicuro che qualcuno dei browser differisca, ma ti incoraggio a testare in Firefox, Safari e IE.


226
Un potenziale problema con questo metodo è che stai sovrascrivendo l'evento e quindi non puoi associare più azioni a un evento. La combinazione addEventListener / attachEvent è il modo migliore per rendere il tuo javascript amichevole con qualsiasi altro script che potrebbe essere in esecuzione sulla pagina.
MyItchyChin

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

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

16
@SubOne un esempio perfetto di come non si dovrebbe mai farlo.
Eugene Pankov,

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

561

Prima di tutto, so che il addEventListenermetodo è stato menzionato nei commenti sopra, ma non ho visto alcun codice. Dal momento che è l'approccio preferito, eccolo qui:

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

Ecco un esempio funzionante .


63
Questa è la risposta più semplice.
jacoviza,

7
Sembra la risposta migliore perché non sovrascrivi l'evento window.onresize :-)
James Harrington

27
Molte persone aggiungono listener di eventi anonimi come te in questo esempio, ma non è davvero una buona pratica, perché questo approccio rende impossibile rimuovere questi listener in seguito. Questo non era un problema perché le pagine Web avevano comunque vita breve, ma al giorno d'oggi di AJAX, RIA e SPA stanno diventando una cosa sola. Abbiamo bisogno di un modo per gestire il ciclo di vita degli ascoltatori di eventi. Pertanto, sarebbe meglio scomporre la funzione di ascolto in una funzione separata in modo che possa essere rimossa in seguito con removeEventListener.
Stijn de Witt,

6
perché non tutti possono rispondere così senza tutto il fluff
quemeful

2
Penso che ci sia verità sia nelle risposte di Stijn de Witt che in quelle di quemeful qui. A volte ti preoccupi di rimuovere i listener di eventi, ma nel caso in cui non lo fai, l'aggiunta di tutto quel codice extra come nell'esempio sopra non è necessaria e può sia gonfiare che ridurre la leggibilità. Secondo me, se non immaginate un motivo per cui è necessario rimuovere l'ascoltatore, questo approccio è la soluzione migliore. Puoi sempre riscriverlo in seguito, se necessario. Nella mia esperienza, questi bisogni sorgono solo in situazioni specifiche.
cazort,

524

Non ignorare mai la funzione window.onresize.

Invece, crea una funzione per aggiungere un listener di eventi all'oggetto o all'elemento. Questo verifica e incase che gli ascoltatori non funzionano, quindi sovrascrive la funzione dell'oggetto come ultima risorsa. Questo è il metodo preferito utilizzato in librerie come jQuery.

object: l'elemento o l'oggetto finestra
type: ridimensiona, scorri (tipo evento)
callback: il riferimento della funzione

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

Quindi usare è così:

addEvent(window, "resize", function_reference);

o con una funzione anonima:

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

100
Questa avrebbe dovuto essere la risposta accettata. La sostituzione di onresize è solo una cattiva pratica.
Tiberiu-Ionuț Stan,

8
hah, che succede con tutti i controlli null aggiuntivi? stai cercando di lavorare in Internet Explorer 4.5 o qualcosa del genere?
FlavorScape

1
E ti stai chiedendo come posso chiamare questa funzione per ricevere eventi di ridimensionamento della finestra? Ecco come: addEvent (window, "resize", function_reference); :)
oabarca,

6
Da IE 11, attachEventnon è più supportato. Il modo preferito per il futuro è addEventListener.
Luca,

6
Stai attento con elem == undefined. È possibile (sebbene improbabile) che "indefinito" sia definito localmente come qualcos'altro. stackoverflow.com/questions/8175673/…
Luca,

32

L'evento di ridimensionamento non deve mai essere utilizzato direttamente in quanto viene generato continuamente durante il ridimensionamento.

Utilizzare una funzione di debounce per mitigare le chiamate in eccesso.

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

Ecco un rimbalzo comune che galleggia intorno alla rete, anche se cerca quelli più avanzati come featuerd in 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);
    };
};

Questo può essere usato così ...

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

Non sparerà mai più di una volta ogni 200 ms.

Per le modifiche all'orientamento mobile utilizzare:

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

Ecco una piccola biblioteca che ho messo insieme per occuparmene in modo chiaro.


Apprezzo le informazioni su: debounce (ora sembra un concetto / funzione inestimabile anche se in precedenza avevo resistito usando i timeout in questo modo), lodash (anche se personalmente non sono convinto) e risolvendo l'ambiguità sull'opportunità di utilizzare addEvent come fallback da aggiungereEventListener (solo perché le risposte precedenti non rispondono in modo esplicito ai commenti in merito)
wunth

5
Cordiali saluti dal momento che si utilizza la notazione della funzione freccia ES6, la funzione interna deve avere (...arguments) => {...}(o ...argsper meno confusione) poiché la argumentsvariabile non è più disponibile il loro ambito.
coderatchet

Sono pienamente consapevole che lo snippet non è il mio codice, è solo un esempio.
frontsideup,

Ottima risposta, i problemi perf con il ridimensionamento devono essere affrontati! Il debouncing è un'opzione, un'altra è la semplice limitazione (che potrebbe essere la strada da percorrere se è necessario ridimensionare l'interfaccia utente in "passaggi"). Vedi bencentra.com/code/2015/02/27/optimizing-window-resize.html per esempi
Robin Métral

24

Soluzione per il 2018+:

Dovresti usare ResizeObserver . È una soluzione nativa del browser che offre prestazioni molto migliori rispetto all'utilizzo resizedell'evento. Inoltre, supporta non solo l'evento sul documentma anche su arbitrario 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);

Attualmente, Firefox, Chrome e Safari lo supportano . Per altri browser (e precedenti) è necessario utilizzare un polyfill .


Ancora la migliore risposta nel 2020 imo
Jesse Reza Khorasanee il


16

Credo che la risposta corretta sia già stata fornita da @Alex V, eppure la risposta richiede un po 'di modernizzazione poiché ormai ha più di cinque anni.

Esistono due problemi principali:

  1. Non usare mai objectcome nome di parametro. È una parola riservata. Detto questo, la funzione fornita da @Alex V non funzionerà strict mode.

  2. La addEventfunzione fornita da @Alex V non restituisce event objectse addEventListenerviene utilizzato il metodo. Un altro parametro deve essere aggiunto alla addEventfunzione per consentire ciò.

NOTA: il nuovo parametro su addEventè stato reso facoltativo in modo che la migrazione a questa nuova versione della funzione non interrompa le chiamate precedenti a questa funzione. Saranno supportati tutti gli usi legacy.

Ecco la addEventfunzione aggiornata con queste modifiche:

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

Una chiamata di esempio alla nuova addEventfunzione:

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

Direi che attachEvent non è più rilevante nel 2017.
Vlad Nicula,

@VladNicula Sono d'accordo, ma questa risposta ha due anni.
WebWanderer,

12

Grazie per aver fatto riferimento al mio post sul blog all'indirizzo http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html .

Mentre puoi semplicemente collegarti all'evento standard di ridimensionamento della finestra, scoprirai che in IE, l'evento viene generato una volta per ogni X e una volta per ogni movimento dell'asse Y, risultando in una tonnellata di eventi che possono essere esibiti impatto sul tuo sito se il rendering è un'attività intensiva.

Il mio metodo prevede un breve timeout che viene annullato su eventi successivi in ​​modo che l'evento non venga confuso con il codice fino a quando l'utente non ha terminato il ridimensionamento della finestra.


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

22
Come molti dei commenti sopra dicono, è meglio non sovrascrivere la funzione onresize; piuttosto aggiungi un nuovo evento. Vedi la risposta di Jondlm.
Luca,

6

Il seguente post di blog può esserti utile: Correggere l'evento di ridimensionamento della finestra in IE

Fornisce questo codice:

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
Questo è applicabile solo alle applicazioni ASP.NET
Evgeny Gorb,

2

Le soluzioni sopra menzionate funzioneranno se tutto ciò che vuoi fare è ridimensionare solo la finestra e la finestra. Tuttavia, se si desidera che il ridimensionamento sia propagato agli elementi figlio, è necessario propagare l'evento da soli. Ecco alcuni esempi di codice per farlo:

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

Si noti che un elemento figlio può chiamare

 event.preventDefault();

sull'oggetto evento che viene passato come primo Arg dell'evento di ridimensionamento. Per esempio:

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_];
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.