Evento de redimensionamento da janela JavaScript

Respostas:

640

O jQuery está apenas envolvendo o resizeevento DOM padrão , por exemplo.

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

O jQuery pode fazer algum trabalho para garantir que o evento de redimensionamento seja acionado de forma consistente em todos os navegadores, mas não tenho certeza se algum dos navegadores difere, mas recomendamos que você teste no Firefox, Safari e IE.

olliej
fonte
226
Uma pegadinha em potencial com esse método é que você está substituindo o evento e, portanto, não pode anexar várias ações a um evento. A combinação addEventListener / attachEvent é a melhor maneira de tornar seu javascript compatível com qualquer outro script que possa estar sendo executado na página.
MyItchyChin
4
var onresize = window.onresize; window.onresize = function (evento) {if (tipo de tamanho === 'função') onresize (); / ** ... * /}
SubOne 17/07/2012
230
window.addEventListener('resize', function(){}, true);
WebWanderer 7/11
16
@SubOne é um exemplo perfeito de como nunca se deve fazer isso.
Eugene Pankov
28
ECMAScript 6 : window.onresize = () => { /* code */ };or better:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman
561

Primeiro, sei que o addEventListenermétodo foi mencionado nos comentários acima, mas não vi nenhum código. Como é a abordagem preferida, aqui está:

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

Aqui está uma amostra de trabalho .

Jondlm
fonte
63
Essa é a resposta mais direta.
jacoviza
7
Soa como a melhor resposta porque o seu não substituindo o evento window.onresize :-)
James Harrington
27
Muitas pessoas adicionam ouvintes de eventos anônimos como você neste exemplo, mas isso não é realmente uma boa prática, porque essa abordagem torna impossível removê-los posteriormente. Isso costumava não ser problema, porque as páginas da web tinham vida curta, mas hoje em dia o AJAX, os RIAs e os SPAs estão se tornando um. Precisamos de uma maneira de gerenciar o ciclo de vida dos ouvintes de eventos. Portanto, seria melhor fatorar a função de ouvinte em uma função separada para que possa ser removida posteriormente com removeEventListener.
Stijn de Witt
6
Por que nem todos resposta como esta, sem todo o fluff
quemeful
2
Acho que há verdade nas respostas de Stijn de Witt e de quemeful aqui. Às vezes, você se preocupa em remover os ouvintes de eventos, mas, caso não o faça, a adição de todo esse código extra, como no exemplo acima, é desnecessária e pode inchar e facilitar a leitura. Na minha opinião, se você não vê um motivo para precisar remover o ouvinte, essa abordagem é a melhor solução. Você sempre pode reescrevê-lo mais tarde, se necessário. Na minha experiência, essas necessidades surgem apenas em situações específicas.
cazort 22/02/19
524

Nunca substitua a função window.onresize.

Em vez disso, crie uma função para adicionar um Event Listener ao objeto ou elemento. Isso verifica e encerra os ouvintes não funcionarem, e substitui a função do objeto como último recurso. Este é o método preferido usado em bibliotecas como o jQuery.

object: o elemento ou objeto da janela
type: redimensionar, rolar (tipo de evento)
callback: a referência da função

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

Então use é assim:

addEvent(window, "resize", function_reference);

ou com uma função anônima:

addEvent(window, "resize", function(event) {
  console.log('resized');
});
Alex V
fonte
100
Essa deveria ter sido a resposta aceita. Substituir onresize é apenas uma prática ruim.
Tiberiu-Ionuț Stan
8
hah, o que há com todas as verificações nulas extras? tentando trabalhar no IE 4.5 ou algo assim?
FlavorScape 15/09/12
1
E você está se perguntando como eu chamo essa função para receber eventos de redimensionamento de janelas? Aqui está como: addEvent (window, "redimensionar", function_reference); :)
oabarca
6
Observe que, a partir do IE 11, attachEventnão é mais suportado. A maneira preferida para o futuro é addEventListener.
26414 Luke
6
Tenha cuidado com elem == undefined. É possível (embora improvável) que "indefinido" seja definido localmente como outra coisa. stackoverflow.com/questions/8175673/…
Luke
32

O evento de redimensionamento nunca deve ser usado diretamente, pois é disparado continuamente à medida que redimensionamos.

Use uma função de rejeição para atenuar o excesso de chamadas.

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

Aqui está um debounce comum flutuando pela rede, embora procure por outros mais avançados como feitos em 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);
    };
};

Isso pode ser usado assim ...

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

Ele nunca dispara mais de uma vez a cada 200ms.

Para alterações na orientação móvel, use:

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

Aqui está uma pequena biblioteca que eu montei para cuidar disso ordenadamente.

frontsideup
fonte
Aprecio as informações sobre: ​​debounce (agora parece um conceito / função inestimável, apesar de anteriormente ter resistido a usar limites de tempo dessa maneira), lodash (embora eu pessoalmente não esteja convencido) e resolver a ambiguidade de usar addEvent como fallback para addEventListener (só porque respostas mais velhos realmente não abordar explicitamente os comentários relativos a esta)
wunth
5
Para sua informação, uma vez que você está usando a notação de função de seta ES6, a função interna precisa ter (...arguments) => {...}(ou ...argspara menos confusão), pois a argumentsvariável não está mais disponível em seu escopo.
Codecatchet #
Estou ciente de que esse snippet não é meu código, é apenas um exemplo.
Frontsideup
Ótima resposta, os problemas de desempenho com redimensionamento precisam ser abordados! A rejeição é uma opção, outra é a otimização simples (que pode ser o caminho a percorrer se você precisar redimensionar sua interface do usuário em "etapas"). Veja bencentra.com/code/2015/02/27/optimizing-window-resize.html para exemplos
Robin Métral
24

Solução para 2018+:

Você deve usar ResizeObserver . É uma solução nativa do navegador que tem um desempenho muito melhor do que usar o resizeevento. Além disso, ele não apenas suporta o evento no, documentmas também no arbitrário 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);

Atualmente, o Firefox, Chrome e Safari suportam . Para outros navegadores (e mais antigos), é necessário usar um polyfill .

str
fonte
Ainda a melhor resposta em 2020 imo
Jesse Reza Khorasanee
16

Acredito que a resposta correta já tenha sido fornecida pelo @Alex V, mas a resposta exige alguma modernização, pois ela tem mais de cinco anos.

Existem dois problemas principais:

  1. Nunca use objectcomo um nome de parâmetro. É uma palavra reservered. Com isso dito, a função fornecida do @Alex V não funcionará strict mode.

  2. A addEventfunção fornecida pelo @Alex V não retorna event objectse o addEventListenermétodo for usado. Outro parâmetro deve ser adicionado à addEventfunção para permitir isso.

NOTA: O novo parâmetro para addEventfoi tornado opcional para que a migração para esta nova versão da função não interrompa nenhuma chamada anterior para esta função. Todos os usos herdados serão suportados.

Aqui está a addEventfunção atualizada com estas alterações:

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

Um exemplo de chamada para a nova addEventfunção:

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
fonte
Eu diria que o attachEvent não é mais relevante em 2017.
Vlad Nicula 17/03
@VladNicula Eu concordo, mas esta resposta tem dois anos.
WebWanderer 17/03/19
12

Obrigado por consultar a postagem do meu blog em http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html .

Enquanto você pode simplesmente conectar-se ao evento de redimensionamento de janela padrão, verá que, no IE, o evento é disparado uma vez para cada movimento do eixo X e uma vez para cada eixo Y, resultando em uma tonelada de eventos sendo disparados que podem ter um desempenho impacto no seu site se a renderização for uma tarefa intensiva.

Meu método envolve um curto tempo limite que é cancelado em eventos subseqüentes, para que o evento não chegue ao seu código até que o usuário termine de redimensionar a janela.

Steven
fonte
7
window.onresize = function() {
    // your code
};
saravanakumar
fonte
22
Como muitos dos comentários acima dizem, é melhor não substituir a função onresize; em vez disso, adicione um novo evento. Veja a resposta de Jondlm.
26414 Luke
6

A seguinte postagem no blog pode ser útil para você: Corrigindo o evento de redimensionamento de janela no IE

Ele fornece este código:

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
fonte
6
Este é aplicável apenas a aplicações ASP.NET
Evgeny Gorb
2

As soluções já mencionadas acima funcionarão se tudo que você quiser fazer é redimensionar a janela e apenas a janela. No entanto, se você deseja que o redimensionamento seja propagado para elementos filho, será necessário propagar o evento você mesmo. Aqui está um exemplo de código para fazer isso:

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

Observe que um elemento filho pode chamar

 event.preventDefault();

no objeto de evento que é passado como o primeiro Arg do evento de redimensionamento. Por exemplo:

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

</script>
Rob Herring
fonte
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_];
        }
    }
}
O INCRÍVEL
fonte