JavaScript / JQuery: $ (window). Redimensionar como disparar APÓS o redimensionamento ser concluído?


235

Estou usando o JQuery como tal:

$(window).resize(function() { ... });

No entanto, parece que, se a pessoa redimensionar manualmente as janelas do navegador, arrastando a borda da janela para aumentá-la / diminuir, o .resizeevento acima será acionado várias vezes.

Pergunta: Como chamo uma função APÓS o redimensionamento da janela do navegador concluído (para que o evento seja acionado apenas uma vez)?


Veja esta resposta: stackoverflow.com/questions/667426/… Envolve o uso de tempos limite para atrasar a execução de sua função.
— Alastair Pitts

Eu não sei se isso é possível, você pode tentar este plugin embora benalman.com/projects/jquery-resize-plugin
— BrunoLM

A propósito, notei que isso é muito útil em navegadores móveis que tendem a ocultar gradualmente a barra de endereços quando o usuário rola para baixo, redimensionando a tela. Eu esperava também redimensionamento do ecrã para acontecer somente no ambiente de trabalho ...
— MakisH

Respostas:


299

Aqui está uma modificação da solução do CMS que pode ser chamada em vários locais no seu código:

var waitForFinalEvent = (function () {
  var timers = {};
  return function (callback, ms, uniqueId) {
    if (!uniqueId) {
      uniqueId = "Don't call this twice without a uniqueId";
    }
    if (timers[uniqueId]) {
      clearTimeout (timers[uniqueId]);
    }
    timers[uniqueId] = setTimeout(callback, ms);
  };
})();

Uso:

$(window).resize(function () {
    waitForFinalEvent(function(){
      alert('Resize...');
      //...
    }, 500, "some unique string");
});

A solução do CMS é boa se você a chamar apenas uma vez, mas se a chamar várias vezes, por exemplo, se partes diferentes do seu código configurarem retornos de chamada separados para redimensionar janelas, haverá falha porque eles compartilham a timervariável.

Com essa modificação, você fornece um ID exclusivo para cada retorno de chamada, e esses IDs exclusivos são usados ​​para manter todos os eventos de tempo limite separados.


2
Eu <3 u, eu combinei isso enquanto redimensionava gráficos Highcharts em tela cheia (não html5) e funciona muito bem.
— Michael J. Calkins

Absolutamente incrível!
— Starkers

2
Como eu me beneficiei tanto com sua resposta, pensei em compartilhar um protótipo funcional do seu código fornecido para o resto da comunidade: jsfiddle.net/h6h2pzpu/3 . Aprecie todos!
— Jonas Stawski 27/08/15

1
Tudo isso é perfeito, mas atrasa a execução da função real pela quantidade de milissegundos (ms), que pode ser MUITO INDESEJÁVEL.
— Tomas M

Isso simplesmente perfeito: existe uma maneira de obter o último redimensionamento e não precisar retransmitir esses milissegundos? De qualquer forma, isso acabou de salvar o meu dia: ') Obrigado.
— Leo

138

Eu prefiro criar um evento:

$(window).bind('resizeEnd', function() {
    //do something, window hasn't changed size in 500ms
});

Aqui está como você o cria:

 $(window).resize(function() {
        if(this.resizeTO) clearTimeout(this.resizeTO);
        this.resizeTO = setTimeout(function() {
            $(this).trigger('resizeEnd');
        }, 500);
    });

Você pode ter isso em um arquivo javascript global em algum lugar.


Eu usei esta solução. Mas, a longo prazo, gostaria de implementar o mesmo que a solução de brahn.
— Bharat Patil

isso permite que você vincular a esse evento em todo o lugar, não apenas em uma função, supondo que você tem várias páginas / .js que exigem reações separadas para isso é claro
— hanzolo

Isto não funcionou para mim, mas DusanV resposta fez o trabalho
— lightbyte

123

Eu uso a seguinte função para atrasar ações repetidas, ele funcionará para o seu caso:

var delay = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  };
})();

Uso:

$(window).resize(function() {
    delay(function(){
      alert('Resize...');
      //...
    }, 500);
});

A função de retorno de chamada transmitida a ele será executada somente quando a última chamada para atrasar for feita após o período especificado, caso contrário, um timer será redefinido. Acho isso útil para outros fins, como detectar quando o usuário parou de digitar etc. ..


5
Eu acho que essa abordagem pode falhar se usada várias vezes (por exemplo, se partes diferentes do retorno de chamada de configuração de código $(window).resize) forem porque todos eles compartilharão a timervariável. Veja minha resposta abaixo para a solução proposta.
— Brahn

Muito agradável! Funciona como um encanto! Como suas respostas ... simples e elegante!
— Sr. Pumpkin

74

Se você tiver o Underscore.js instalado, poderá:

$(window).resize(_.debounce(function(){
    alert("Resized");
},500));

1
Mesmo se você não quiser incluir sublinhado pelo menos agarrar a fonte para isso: underscorejs.org/docs/underscore.html#section-67
— tybro0103

Debounce é a técnica correta aqui, é apenas uma questão de implementações. E essa é a implementação superior se o Underscore / Lodash já for uma dependência do projeto.
— Fatore Mystic

Agora é isso que eu estou usando,
— Bharat Patil

20

Algumas das soluções mencionadas anteriormente não funcionaram para mim, embora sejam de uso mais geral. Como alternativa, eu encontrei este que fez o trabalho no redimensionamento da janela:

$(window).bind('resize', function(e){
    window.resizeEvt;
    $(window).resize(function(){
        clearTimeout(window.resizeEvt);
        window.resizeEvt = setTimeout(function(){
        //code to do after window is resized
        }, 250);
    });
});

1
Apenas o seu exemplo funcionou para mim ... os outros acima não! Não sei por que sua resposta não foi selecionada.
— Mumbo Jumbo

Eu não entendo por que para pegar o evento de redimensionamento dentro do evento de redimensionamento, mas funciona para mim também ...
— lightbyte

Mumbo Jumbo, acho que porque outros se concentram na generalização, procurando solução para qualquer problema desse tipo (várias chamadas de uma função).
— DusanV

lightbyte, é porque você precisa interromper os eventos anteriores cada vez que a função é chamada.
— DusanV

13

Muito obrigado a David Walsh, aqui está uma versão básica do debounce de sublinhado.

Código:

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Uso simples:

var myEfficientFn = debounce(function() {
    // All the taxing stuff you do
}, 250);

$(window).on('resize', myEfficientFn);

Ref: http://davidwalsh.name/javascript-debounce-function


6

Na verdade, como eu sei, você não pode executar algumas ações exatamente quando o redimensionamento está desativado, simplesmente porque você não conhece as ações do usuário futuro. Mas você pode assumir o tempo decorrido entre dois eventos de redimensionamento; portanto, se você esperar um pouco mais que esse tempo e nenhum redimensionamento for feito, poderá chamar sua função.
A idéia é que usamos setTimeoute seu ID para salvá-lo ou excluí-lo. Por exemplo, sabemos que o tempo entre dois eventos de redimensionamento é de 500 ms; portanto, esperaremos 750 ms.

var a;
$(window).resize(function(){
  clearTimeout(a);
  a = setTimeout(function(){
    // call your function
  },750);
});


3

Declarar ouvinte com atraso global:

var resize_timeout;

$(window).on('resize orientationchange', function(){
    clearTimeout(resize_timeout);

    resize_timeout = setTimeout(function(){
        $(window).trigger('resized');
    }, 250);
});

E abaixo, use os ouvintes para o resizedevento como desejar:

$(window).on('resized', function(){
    console.log('resized');
});

Obrigado, essa é a melhor solução atualmente. Também testei que 250ms está funcionando da melhor maneira ao redimensionar a janela.
— AlexioVay


2

Plugin jQuery simples para evento de redimensionamento de janela atrasado.

SINTAXE:

Adicionar nova função para redimensionar evento

jQuery(window).resizeDelayed( func, delay, id ); // delay and id are optional

Remova a função (declarando seu ID) adicionada anteriormente

jQuery(window).resizeDelayed( false, id );

Remova todas as funções

jQuery(window).resizeDelayed( false );

USO:

// ADD SOME FUNCTIONS TO RESIZE EVENT
jQuery(window).resizeDelayed( function(){ console.log( 'first event - should run after 0.4 seconds'); }, 400,  'id-first-event' );
jQuery(window).resizeDelayed( function(){ console.log('second event - should run after 1.5 seconds'); }, 1500, 'id-second-event' );
jQuery(window).resizeDelayed( function(){ console.log( 'third event - should run after 3.0 seconds'); }, 3000, 'id-third-event' );

// LETS DELETE THE SECOND ONE
jQuery(window).resizeDelayed( false, 'id-second-event' );

// LETS ADD ONE WITH AUTOGENERATED ID(THIS COULDNT BE DELETED LATER) AND DEFAULT TIMEOUT (500ms)
jQuery(window).resizeDelayed( function(){ console.log('newest event - should run after 0.5 second'); } );

// LETS CALL RESIZE EVENT MANUALLY MULTIPLE TIMES (OR YOU CAN RESIZE YOUR BROWSER WINDOW) TO SEE WHAT WILL HAPPEN
jQuery(window).resize().resize().resize().resize().resize().resize().resize();

SAÍDA DE USO:

first event - should run after 0.4 seconds
newest event - should run after 0.5 second
third event - should run after 3.0 seconds

PLUGAR:

jQuery.fn.resizeDelayed = (function(){

    // >>> THIS PART RUNS ONLY ONCE - RIGHT NOW

    var rd_funcs = [], rd_counter = 1, foreachResizeFunction = function( func ){ for( var index in rd_funcs ) { func(index); } };

    // REGISTER JQUERY RESIZE EVENT HANDLER
    jQuery(window).resize(function() {

        // SET/RESET TIMEOUT ON EACH REGISTERED FUNCTION
        foreachResizeFunction(function(index){

            // IF THIS FUNCTION IS MANUALLY DISABLED ( by calling jQuery(window).resizeDelayed(false, 'id') ),
            // THEN JUST CONTINUE TO NEXT ONE
            if( rd_funcs[index] === false )
                return; // CONTINUE;

            // IF setTimeout IS ALREADY SET, THAT MEANS THAT WE SHOULD RESET IT BECAUSE ITS CALLED BEFORE DURATION TIME EXPIRES
            if( rd_funcs[index].timeout !== false )
                clearTimeout( rd_funcs[index].timeout );

            // SET NEW TIMEOUT BY RESPECTING DURATION TIME
            rd_funcs[index].timeout = setTimeout( rd_funcs[index].func, rd_funcs[index].delay );

        });

    });

    // <<< THIS PART RUNS ONLY ONCE - RIGHT NOW

    // RETURN THE FUNCTION WHICH JQUERY SHOULD USE WHEN jQuery(window).resizeDelayed(...) IS CALLED
    return function( func_or_false, delay_or_id, id ){

        // FIRST PARAM SHOULD BE SET!
        if( typeof func_or_false == "undefined" ){

            console.log( 'jQuery(window).resizeDelayed(...) REQUIRES AT LEAST 1 PARAMETER!' );
            return this; // RETURN JQUERY OBJECT

        }

        // SHOULD WE DELETE THE EXISTING FUNCTION(S) INSTEAD OF CREATING A NEW ONE?
        if( func_or_false == false ){

            // DELETE ALL REGISTERED FUNCTIONS?
            if( typeof delay_or_id == "undefined" ){

                // CLEAR ALL setTimeout's FIRST
                foreachResizeFunction(function(index){

                    if( typeof rd_funcs[index] != "undefined" && rd_funcs[index].timeout !== false )
                        clearTimeout( rd_funcs[index].timeout );

                });

                rd_funcs = [];

                return this; // RETURN JQUERY OBJECT

            }
            // DELETE ONLY THE FUNCTION WITH SPECIFIC ID?
            else if( typeof rd_funcs[delay_or_id] != "undefined" ){

                // CLEAR setTimeout FIRST
                if( rd_funcs[delay_or_id].timeout !== false )
                    clearTimeout( rd_funcs[delay_or_id].timeout );

                rd_funcs[delay_or_id] = false;

                return this; // RETURN JQUERY OBJECT

            }

        }

        // NOW, FIRST PARAM MUST BE THE FUNCTION
        if( typeof func_or_false != "function" )
            return this; // RETURN JQUERY OBJECT

        // SET THE DEFAULT DELAY TIME IF ITS NOT ALREADY SET
        if( typeof delay_or_id == "undefined" || isNaN(delay_or_id) )
            delay_or_id = 500;

        // SET THE DEFAULT ID IF ITS NOT ALREADY SET
        if( typeof id == "undefined" )
            id = rd_counter;

        // ADD NEW FUNCTION TO RESIZE EVENT
        rd_funcs[id] = {
            func : func_or_false,
            delay: delay_or_id,
            timeout : false
        };

        rd_counter++;

        return this; // RETURN JQUERY OBJECT

    }

})();

1

Supondo que o cursor do mouse retorne ao documento após o redimensionamento da janela, podemos criar um comportamento de retorno de chamada com o evento onmouseover. Não esqueça que esta solução pode não funcionar em telas ativadas para toque conforme o esperado.

var resizeTimer;
var resized = false;
$(window).resize(function() {
   clearTimeout(resizeTimer);
   resizeTimer = setTimeout(function() {
       if(!resized) {
           resized = true;
           $(document).mouseover(function() {
               resized = false;
               // do something here
               $(this).unbind("mouseover");
           })
       }
    }, 500);
});

Ótimo para sites somente para desktop baseados em mouse, mas o evento de mouseover nunca acontecerá se, por exemplo, o usuário estiver em um celular e mudar de paisagem para retrato ou se redimensionar a janela em uma área de trabalho com tela de toque.
— precisa saber é o seguinte

Você pode redimensionar a janela do navegador com a ajuda de teclado na últimas oses Windows como Win-Seta-Esquerda Win-seta para a direita, etc ...
— LU4

0

Isto é o que eu implementei:

$ (window) .resize (function () {setTimeout (someFunction, 500);});

podemos limpar o setTimeout se esperamos que o redimensionamento ocorra menos que500ms

Boa sorte...

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.