Como detectar a dimensão do DIV alterada?

351

Eu tenho o seguinte exemplo html, há um DIV que tem 100% de largura. Ele contém alguns elementos. Ao realizar o redimensionamento das janelas, os elementos internos podem ser reposicionados e a dimensão da div pode mudar. Estou perguntando se é possível conectar o evento de mudança de dimensão da div? e como fazer isso? Atualmente, eu vinculo a função de retorno de chamada ao evento de redimensionamento do jQuery no DIV de destino, no entanto, nenhum log do console é gerado, veja abaixo:

Antes de redimensionar insira a descrição da imagem aqui

<html>
<head>
    <script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" language="javascript">
            $('#test_div').bind('resize', function(){
                console.log('resized');
            });
    </script>
</head>
<body>
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
    </div>
</body>
</html>
William Choi
fonte
7
Isso não funcionará porque você está vinculando o evento redimensionar ao elemento div especificado. Mas o evento resize será acionado para a janela e não para o seu elemento.
Fatih Acet
Você pode usar setIntervalaqui como uma possível solução. Você sempre pode vincular clearIntervala um clique no botão para interromper o loop assim que seu trabalho estiver concluído.
Peter Darmis
11
Desde 2020, o ResizeObserver funciona em todos os principais navegadores (Chrome, Safari, Firefox, Edge), exceto no IE. caniuse.com/#feat=resizeobserver
Dan

Respostas:

264

Existe um método muito eficiente para determinar se o tamanho de um elemento foi alterado.

http://marcj.github.io/css-element-queries/

Esta biblioteca possui uma classe ResizeSensorque pode ser usada para a detecção de redimensionamento.
Ele usa uma abordagem baseada em eventos, por isso é muito rápido e não perde tempo de CPU.

Exemplo:

new ResizeSensor(jQuery('#divId'), function(){ 
    console.log('content dimension changed');
});

Por favor, não use o plugin jQuery onresize, pois ele setTimeout()combina com a leitura do DOM clientHeight/ clientWidthpropriedades em um loop para verificar se há alterações.
Isso é incrível, lento e impreciso, pois causa uma desorganização no layout .

Divulgação: estou diretamente associado a esta biblioteca.

Marc J. Schmidt
fonte
8
@jake, o suporte ao IE11 agora está implementado.
Marc J. Schmidt
15
@Aletheios, você deve dar uma olhada. requestAnimationFrame não é para detecção de dimensão lenta, mas exatamente o oposto: suaviza todos esses números extremos de eventos disparados pelo sensor de redimensionamento baseado em evento real para economizar tempo de CPU. Consulte os documentos atualizados em github.com/marcj/css-element-queries/blob/master/src/…
Marc J. Schmidt
6
@Aletheios Eu acho que você perdeu um ponto: setTimeout não é apenas impreciso, mas lento como o inferno. Um requestAnimationFrame que verifica um booleano simples é ordens de magnitude mais rápido que um setTimeout que verifica o tempo todo em relação às propriedades do DOM. Além disso, setTimeout também é chamado a cada poucos milissegundos.
Marc J. Schmidt
9
@ Orwellophile você obviamente não entendeu nada. Pare de diminuir a votação de respostas onde você não tem idéia de como isso funciona internamente. Novamente: css-element-query: usa um evento de redimensionamento real que é acionado toda vez que a dimensão é alterada. Como você recebia muitos eventos (por exemplo, arrastar e soltar), adicionou requestAnimationFrame verificando uma variável booleana simples para suavizar esses eventos acionados para 1 / frame. plugin jquery: Usa um setTimeout verificando todo o tempo os objetos de layout do DOM (clientHeight etc), onde cada verificação é muito lenta, mas precisa ser verificada com frequência para ter a mesma funcionalidade.
Marc J. Schmidt
9
@Aletheios, @Orwellophile e qualquer pessoa que possa ter sido enganada por eles: requestAnimationFramevs setTimeouté irrelevante, esta biblioteca não se repete . requestAnimationFrameé usado apenas para rejeitar / acelerar a frequência de chamadas de retorno de chamada, ele não pesquisa . O MutationObserver poderia, teoricamente, ser usado para um efeito semelhante, mas não em navegadores antigos, diferentemente disso. Isso é extremamente inteligente.
Han Seoul-Oh
251

Um novo padrão para isso é a API Resize Observer, disponível no Chrome 64.

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me</textarea><br>

Redimensionar observador

Spec: https://wicg.github.io/ResizeObserver

Polyfills: https://github.com/WICG/ResizeObserver/issues/3

Edição do Firefox: https://bugzil.la/1272409

Problema no Safari: http://wkb.ug/157743

Suporte atual: http://caniuse.com/#feat=resizeobserver

Daniel Herr
fonte
3
ainda não é útil para sites de produção, pois apenas o Chrome suporta no momento. Mas definitivamente a melhor solução aqui! btw, aqui está uma rápida visão geral do status da implementação: chromestatus.com/feature/5705346022637568
Philipp
8
@ Philipp Existe um polyfill.
Daniel Herr
2
Parece que ainda é um recurso experimental em todos os navegadores caniuse.com/#feat=resizeobserver
Francesc Rosas
5
Até 2 anos após esta resposta, o suporte ao navegador é sombrio: caniuse.com/#search=resizeobserver
Scrimothy
2
Funciona como um encanto no Chrome e no FF mais recentes.
Klemen Tušar 22/10/19
32

Você precisa vincular o resizeevento ao windowobjeto, não a um elemento html genérico.

Você pode usar isso:

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

e dentro da função de retorno de chamada, você pode verificar a nova largura da sua divchamada

$('.a-selector').width();

Portanto, a resposta para sua pergunta é não , você não pode vincular o resizeevento a uma div.

Alessandro Vendruscolo
fonte
124
esta resposta não é boa o suficiente. alterações de tamanho podem ocorrer sem QUALQUER redimensionamento da janela. em absoluto.
vsync
9
por exemplo, quando você tem um elemento divisor ou apenas anexa algum texto ou outro conteúdo a um elemento.
Günter Zöchbauer
@anu não é verdade, você pode ter, por exemplo, modificação do DOM via javascript, fazendo com que o CSS se aplique à nova estrutura, resultando em diferentes tamanhos de layout de cada contêiner.
Antoniossss
29

A longo prazo, você poderá usar o ResizeObserver .

new ResizeObserver(callback).observe(element);

Infelizmente, atualmente não é suportado por padrão em muitos navegadores.

Enquanto isso, você pode usar funções como as seguintes. Desde então, a maioria das alterações no tamanho do elemento virá do redimensionamento da janela ou da alteração de algo no DOM. Você pode ouvir o redimensionamento da janela com o evento de redimensionamento da janela e as alterações do DOM usando o MutationObserver .

Aqui está um exemplo de uma função que retornará a ligação quando o tamanho do elemento fornecido for alterado como resultado de um desses eventos:

var onResize = function(element, callback) {
  if (!onResize.watchedElementData) {
    // First time we are called, create a list of watched elements
    // and hook up the event listeners.
    onResize.watchedElementData = [];

    var checkForChanges = function() {
      onResize.watchedElementData.forEach(function(data) {
        if (data.element.offsetWidth !== data.offsetWidth ||
            data.element.offsetHeight !== data.offsetHeight) {
          data.offsetWidth = data.element.offsetWidth;
          data.offsetHeight = data.element.offsetHeight;
          data.callback();
        }
      });
    };

    // Listen to the window's size changes
    window.addEventListener('resize', checkForChanges);

    // Listen to changes on the elements in the page that affect layout 
    var observer = new MutationObserver(checkForChanges);
    observer.observe(document.body, { 
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true 
    });
  }

  // Save the element we are watching
  onResize.watchedElementData.push({
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  });
};
nkron
fonte
11
Infelizmente, parece que o MutationObserver não pode detectar alterações no Shadow DOM.
Ajedi32
@ nkron, infelizmente, se você usar o redimensionamento CSS3 , o redimensionamento pode acontecer quando o usuário redimensiona manualmente. Este evento não pode ser capturado.
Pacerier 19/02/16
@ Ajedi32 Sim, mas você pode usar o MutationObserver dentro do ShadowDOM. O que quero dizer é que, em vez de observar o bodyexemplo, é possível assistir diretamente a um elemento. Isso é realmente mais eficiente e eficiente do que observar todo o corpo.
trusktr
@ Ajedi32 Bem, o único problema é que, se a árvore do DOM DOM estiver fechada, você não poderá acessar os internos, mas não acho que isso seja algo que você precise fazer e se precise observar uma árvore fechada assim, pode haver um problema no design. Idealmente, você só precisa observar seus próprios elementos aos quais tem acesso. Um componente Shadow-DOM que exige que você observe o dimensionamento interno pode não ter sido projetado corretamente. Você tem um exemplo específico? Nesse caso, talvez eu possa ajudar a sugerir uma solução (porque também estou interessado nela, mas ainda não tenho exemplo).
trusktr
@trusktr Eu não tenho um MCVE no momento, mas basicamente qualquer elemento do DOM DOM que possa mudar de tamanho como resultado de alguma entrada do usuário seria suficiente para desencadear esse problema. Uma caixa que se expande com algumas informações adicionais quando clicada, por exemplo. Observe que estou observando a página, não o elemento individual, porque quero rolar automaticamente para baixo quando o tamanho da página aumentar, independentemente do motivo. A expansão do elemento DOM DOM da sombra é apenas uma das muitas razões possíveis pelas quais a página pode ficar mais longa.
Ajedi32
24

O ResizeSensor.js faz parte de uma enorme biblioteca, mas reduzi sua funcionalidade para ISTO :

function ResizeSensor(element, callback)
{
    let zIndex = parseInt(getComputedStyle(element));
    if(isNaN(zIndex)) { zIndex = 0; };
    zIndex--;

    let expand = document.createElement('div');
    expand.style.position = "absolute";
    expand.style.left = "0px";
    expand.style.top = "0px";
    expand.style.right = "0px";
    expand.style.bottom = "0px";
    expand.style.overflow = "hidden";
    expand.style.zIndex = zIndex;
    expand.style.visibility = "hidden";

    let expandChild = document.createElement('div');
    expandChild.style.position = "absolute";
    expandChild.style.left = "0px";
    expandChild.style.top = "0px";
    expandChild.style.width = "10000000px";
    expandChild.style.height = "10000000px";
    expand.appendChild(expandChild);

    let shrink = document.createElement('div');
    shrink.style.position = "absolute";
    shrink.style.left = "0px";
    shrink.style.top = "0px";
    shrink.style.right = "0px";
    shrink.style.bottom = "0px";
    shrink.style.overflow = "hidden";
    shrink.style.zIndex = zIndex;
    shrink.style.visibility = "hidden";

    let shrinkChild = document.createElement('div');
    shrinkChild.style.position = "absolute";
    shrinkChild.style.left = "0px";
    shrinkChild.style.top = "0px";
    shrinkChild.style.width = "200%";
    shrinkChild.style.height = "200%";
    shrink.appendChild(shrinkChild);

    element.appendChild(expand);
    element.appendChild(shrink);

    function setScroll()
    {
        expand.scrollLeft = 10000000;
        expand.scrollTop = 10000000;

        shrink.scrollLeft = 10000000;
        shrink.scrollTop = 10000000;
    };
    setScroll();

    let size = element.getBoundingClientRect();

    let currentWidth = size.width;
    let currentHeight = size.height;

    let onScroll = function()
    {
        let size = element.getBoundingClientRect();

        let newWidth = size.width;
        let newHeight = size.height;

        if(newWidth != currentWidth || newHeight != currentHeight)
        {
            currentWidth = newWidth;
            currentHeight = newHeight;

            callback();
        }

        setScroll();
    };

    expand.addEventListener('scroll', onScroll);
    shrink.addEventListener('scroll', onScroll);
};

Como usá-lo:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});
Martin Wantke
fonte
É isso que os gráficos js fazem.
Antoniossss 17/01
Obrigado por comprimir isso. Vou testá-lo :)
Tony K.
Há algo faltando nessa expressãoparseInt( getComputedStyle(element) )
GetFree 7/18
2
Estou confuso como é "deixe zIndex = parseInt (getComputedStyle (elemento));" válido? Eu suponho que você queria dizer: "vamos zIndex = parseInt (getComputedStyle (elemento) .zIndex);
Ryan Badour
11
A solução / código acima não detecta todos os eventos de redimensionamento (por exemplo, se um contêiner é redimensionado para um objeto fixo, ele não detecta o redimensionamento para eventos filho. Consulte jsfiddle.net/8md2rfsy/1 ). A resposta aceita funciona (descomente as respectivas linhas).
newBee 29/04/19
21

Eu não recomendo o setTimeout()hack, pois diminui o desempenho! Em vez disso, você pode usar observadores de mutação DOM para ouvir a alteração do tamanho da Div.

JS:

var observer = new MutationObserver(function(mutations) {
    console.log('size changed!');
  });
  var target = document.querySelector('.mydiv');
  observer.observe(target, {
    attributes: true
  });

HTML:

<div class='mydiv'>
</div>

Aqui está o violino
Tente alterar o tamanho da div.


Você também pode agrupar seu método no debouncemétodo para melhorar a eficiência. debounceacionará seu método a cada x milissegundos em vez de acionar a cada milissegundo que o DIV está sendo redimensionado.

JerryGoyal
fonte
9
O único problema com este é que ele não informa uma alteração, a menos que uma mutação realmente aconteça com o elemento. Se o elemento for redimensionado devido à adição de outros elementos, isso não funcionará.
22718 Tony
Concordo com @TonyK, este é o meu único problema com MutationObserver e agora estou procurando uma biblioteca de elementos de redimensionamento.
Murhaf Sousli
@JerryGoyal Não está funcionando quando a div contém a tag <img>. Na primeira instância, a imagem não é carregada e o tamanho do div é definido como 0; após o carregamento, o tamanho do div é alterado, mas o observador não é acionado
Santhosh
15

A melhor solução seria usar as chamadas consultas de elemento . No entanto, eles não são padrão, não existe especificação - e a única opção é usar uma das bibliotecas / polyfills disponíveis, se você quiser seguir esse caminho.

A idéia por trás das consultas de elemento é permitir que um determinado contêiner na página responda ao espaço fornecido a ele. Isso permitirá escrever um componente uma vez e soltá-lo em qualquer lugar da página, enquanto ajusta seu conteúdo para o tamanho atual. Não importa qual é o tamanho da janela. Essa é a primeira diferença que vemos entre consultas de elemento e consultas de mídia. Todo mundo espera que, em algum momento, seja criada uma especificação que padronize as consultas de elementos (ou algo que atinja o mesmo objetivo) e as torne nativas, limpas, simples e robustas. A maioria das pessoas concorda que as consultas de mídia são bastante limitadas e não ajudam no design modular e na capacidade de resposta verdadeira.

Existem alguns polyfills / bibliotecas que resolvem o problema de maneiras diferentes (podem ser chamadas de soluções alternativas em vez de soluções):

Eu já vi outras soluções propostas para problemas semelhantes. Geralmente eles usam temporizadores ou o tamanho da janela / janela de visualização embaixo do capô, o que não é uma solução real. Além disso, acho que idealmente isso deve ser resolvido principalmente em CSS, e não em javascript ou html.

Stan
fonte
+1 para consultas de elementos, mas não tenho esperanças de vê-las em breve. Não há sequer um rascunho de especificação neste momento, AFAIK ... talvez um de nós, partes interessadas, deva montar um e enviá-lo?
Rob Evans
11
Essa é uma boa ideia, é claro. Vai levar muito tempo para chegar a uma versão final, é preciso chamar muita atenção. Projetar isso de uma maneira boa não me parece trivial. Compatibilidade cross-browser, dependências circulares, depuração, legibilidade e manutenção etc. Então, vamos começar o mais cedo possível :)
Stan
@ Stan, acho que essa resposta pode ser melhor adicionando mais detalhes sobre o que é a consulta de elemento.
Pacerier 19/02/16
15

Encontrei esta biblioteca para trabalhar quando a solução de MarcJ não funcionou:

https://github.com/sdecima/javascript-detect-element-resize

É muito leve e detecta até redimensionamentos naturais via CSS ou simplesmente o carregamento / renderização de HTML.

Exemplo de código (extraído do link):

<script type="text/javascript" src="detect-element-resize.js"></script>
<script type="text/javascript">
  var resizeElement = document.getElementById('resizeElement'),
      resizeCallback = function() {
          /* do something */
      };
  addResizeListener(resizeElement, resizeCallback);
  removeResizeListener(resizeElement, resizeCallback);
</script>
Joshcomley
fonte
É isso. 147 linhas, usa eventos de rolagem. Leia este código se desejar obter a resposta completa e verdadeira sobre a melhor forma de detectar alterações na dimensão div. Dica: não é "apenas use esta biblioteca".
Seph Reed
11
As pessoas devem dar uma olhada nesse problema antes de experimentar esta biblioteca.
Louis Louis
13

Dê uma olhada neste http://benalman.com/code/projects/jquery-resize/examples/resize/

Tem vários exemplos. Tente redimensionar sua janela e veja como os elementos dentro dos elementos do contêiner foram ajustados.

Exemplo com js fiddle para explicar como fazê-lo funcionar.
Dê uma olhada neste violino http://jsfiddle.net/sgsqJ/4/

Nesse evento resize () é vinculado a um elemento que possui a classe "test" e também ao objeto window e no redimensionamento de retorno de chamada do objeto $ ('. Test'). Resize () é chamado.

por exemplo

$('#test_div').bind('resize', function(){
            console.log('resized');
});

$(window).resize(function(){
   $('#test_div').resize();
});
Bharat Patil
fonte
Interessante. Esse jsfiddle trava consistentemente o chrome com o inspetor e é aberto e clico no link "Adicionar mais texto". O Firefox lança erros "muita recursão".
EricP
3
Por favor, não use o plugin de redimensionamento do jQuery. É muito lento e não é preciso também. Veja minha resposta para obter uma solução melhor.
Marc J. Schmidt
24
Isso NÃO detecta diretamente as alterações de dimensão. é apenas um subproduto de um ouvinte de redimensionamento. uma mudança de dimensão pode acontecer de várias outras maneiras.
vsync
4
E se o redimensionamento da div for de mudança de estilo ou dom e não por redimensionamento de janela?
temor
9

Você pode usar iframeou objectusar contentWindowou contentDocumentredimensionar. Sem setIntervalousetTimeout

Os passos:

  1. Defina a posição do seu elemento como relative
  2. Adicione dentro de um IFRAME oculto absoluto transparente
  3. Ouvir IFRAME.contentWindow- onresizeevento

Um exemplo de HTML:

<div style="height:50px;background-color:red;position:relative;border:1px solid red">
<iframe style=width:100%;height:100%;position:absolute;border:none;background-color:transparent allowtransparency=true>
</iframe>
This is my div
</div>

O Javascript:

$('div').width(100).height(100);
$('div').animate({width:200},2000);

$('object').attr({
    type : 'text/html'
})
$('object').on('resize,onresize,load,onload',function(){
    console.log('ooooooooonload')
})

$($('iframe')[0].contentWindow).on('resize',function(){
    console.log('div changed')
})

Exemplo de execução

JsFiddle: https://jsfiddle.net/qq8p470d/


Ver mais:

Aminadav Glickshtein
fonte
11
Uma observação para aqueles que não usam jquery, IFRAME.contentWindownão estará disponível até que o onloadevento seja disparado no iframe. Além disso, convém adicionar o estilo visibility:hidden;, pois o iframe pode bloquear a entrada do mouse nos elementos por trás dele (parece estar "flutuando" no IE, pelo menos).
James Wilkins
3
Embora isso funcione, é uma solução pesada com a sobrecarga de criar um novo contexto de navegação apenas para observar a mudança de tamanho. Além disso, em alguns casos, não é ideal ou viável alterar a displaypropriedade do elemento.
trusktr
concordado, esta é uma solução terrível como indicado acima #
29er 15/11
Como escreveu solução tão terrível?
Aminadav Glickshtein
esse método funciona bem com players de vídeo e áudio que precisam ser redimensionados. Estou usando esse método para redimensionar a saída wavesurfer.js.
David Clews
8

Somente o objeto de janela gera um evento "redimensionar". A única maneira que eu sei de fazer o que você quer fazer é executar um temporizador de intervalo que verifique periodicamente o tamanho.

Pontudo
fonte
7

var div = document.getElementById('div');
div.addEventListener('resize', (event) => console.log(event.detail));

function checkResize (mutations) {
    var el = mutations[0].target;
    var w = el.clientWidth;
    var h = el.clientHeight;
    
    var isChange = mutations
      .map((m) => m.oldValue + '')
      .some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);

    if (!isChange)
      return;

    var event = new CustomEvent('resize', {detail: {width: w, height: h}});
    el.dispatchEvent(event);
}

var observer = new MutationObserver(checkResize); 
observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
#div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
<div id = "div">DIV</div>

Aikon Mogwai
fonte
7

Surpreendentemente, por mais antigo que seja esse problema, ele ainda é um problema na maioria dos navegadores.

Como já foi dito, o Chrome 64+ é lançado com o Resize Observes de forma nativa, no entanto, as especificações ainda estão sendo ajustadas e o Chrome está atualmente (a partir de 2019-01-29) por trás da última edição da especificação .

Eu já vi alguns polifills ResizeObserver bons na natureza, no entanto, alguns não seguem as especificações de perto e outros têm alguns problemas de cálculo.

Eu precisava desesperadamente desse comportamento para criar alguns componentes da Web responsivos que poderiam ser usados ​​em qualquer aplicativo. Para fazê-los funcionar bem, eles precisam conhecer suas dimensões o tempo todo, para que ResizeObservers parecesse ideal e eu decidi criar um polyfill que seguisse as especificações o mais próximo possível.

Repo: https://github.com/juggle/resize-observer

Demonstração: https://codesandbox.io/s/myqzvpmmy9

Trem
fonte
Definitivamente, é a resposta certa para quem lida com a compatibilidade do navegador IE11 +.
ekfuhrmann
3

Usando o Clay.js ( https://github.com/zzarcon/clay ), é bastante simples detectar alterações no tamanho do elemento:

var el = new Clay('.element');

el.on('resize', function(size) {
    console.log(size.height, size.width);
});
Zzarcon
fonte
7
Forneça a divulgação apropriada, pois é sua biblioteca.
jhpratt GOFUNDME RELICENSING
Isso funcionou para mim, onde o ResizeSensor não funciona, ele quebra meu estilo modal. Obrigado Zzarcon :)
Máxima Alekz
3

Esta postagem do blog me ajudou a detectar com eficiência alterações de tamanho nos elementos DOM.

http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

Como usar este código ...

AppConfig.addResizeListener(document.getElementById('id'), function () {
  //Your code to execute on resize.
});

Código empacotado usado pelo exemplo ...

var AppConfig = AppConfig || {};
AppConfig.ResizeListener = (function () {
    var attachEvent = document.attachEvent;
    var isIE = navigator.userAgent.match(/Trident/);
    var requestFrame = (function () {
        var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
            function (fn) { return window.setTimeout(fn, 20); };
        return function (fn) { return raf(fn); };
    })();

    var cancelFrame = (function () {
        var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
               window.clearTimeout;
        return function (id) { return cancel(id); };
    })();

    function resizeListener(e) {
        var win = e.target || e.srcElement;
        if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
        win.__resizeRAF__ = requestFrame(function () {
            var trigger = win.__resizeTrigger__;
            trigger.__resizeListeners__.forEach(function (fn) {
                fn.call(trigger, e);
            });
        });
    }

    function objectLoad(e) {
        this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
        this.contentDocument.defaultView.addEventListener('resize', resizeListener);
    }

    AppConfig.addResizeListener = function (element, fn) {
        if (!element.__resizeListeners__) {
            element.__resizeListeners__ = [];
            if (attachEvent) {
                element.__resizeTrigger__ = element;
                element.attachEvent('onresize', resizeListener);
            } else {
                if (getComputedStyle(element).position === 'static') element.style.position = 'relative';
                var obj = element.__resizeTrigger__ = document.createElement('object');
                obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
                obj.__resizeElement__ = element;
                obj.onload = objectLoad;
                obj.type = 'text/html';
                if (isIE) element.appendChild(obj);
                obj.data = 'about:blank';
                if (!isIE) element.appendChild(obj);
            }
        }
        element.__resizeListeners__.push(fn);
    };

    AppConfig.removeResizeListener = function (element, fn) {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            if (attachEvent) element.detachEvent('onresize', resizeListener);
            else {
                element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
                element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
            }
        }
    }
})();

Nota: AppConfig é um espaço para nome / objeto que eu uso para organizar funções reutilizáveis. Sinta-se livre para pesquisar e substituir o nome por qualquer coisa que você desejar.

Ben Gripka
fonte
3

Meu plugin jQuery habilita o evento "redimensionar" em todos os elementos e não apenas no window.

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 
Dustin Poissant
fonte
11
Seu link estava apontando para um local que não existe mais. Pesquisei o nome do plug-in e encontrei uma página que corresponde à sua descrição. Como você parece ser o autor do plug-in, também editei o idioma da sua resposta para deixar explícito que esse é o seu trabalho. As regras deste site são tais que, quando você escreve respostas, recomenda o uso de algo que você desenvolveu, deve tornar o relacionamento explícito.
Louis
Esta não é uma ótima solução, porque você executa algumas funções no setTimer repetidamente, o que significa que o navegador está constantemente queimando a CPU, mesmo que nada esteja acontecendo. Os proprietários de laptops e celulares se beneficiam da solução que usa eventos do navegador apenas quando há alguma ação, como usar o evento onScroll.
Roman Zenka
2

Você pode tentar o código no seguinte trecho, que cobre suas necessidades usando javascript comum. ( execute o snippet de código e clique no link de página inteira para acionar o alerta de que a div é redimensionada se você quiser testá-la. ).

Com base no fato de que este é um setIntervaldos 100 milissegundos, eu ousaria dizer que meu PC não achou muita fome de CPU. (0,1% da CPU foi usado como total para todas as guias abertas no Chrome no momento do teste.). Mas, novamente, isso é apenas para uma div, se você quiser fazer isso para uma grande quantidade de elementos, então sim, isso pode exigir muita CPU.

Você sempre pode usar um evento de clique para interromper o cheiro do redimensionamento de div .

var width = 0; 
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized div');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
</div>

Você pode verificar o violino também

ATUALIZAR

var width = 0; 
function myInterval() {
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
return interval;
}
var interval = myInterval();
document.getElementById("clickMe").addEventListener( "click" , function() {
if(typeof interval!=="undefined") {
clearInterval(interval);
alert("stopped div-resize sniffing");
}
});
document.getElementById("clickMeToo").addEventListener( "click" , function() {
myInterval();
alert("started div-resize sniffing");
});
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" id="clickMe" />
        <input type="button" value="button 2" id="clickMeToo" />
        <input type="button" value="button 3" />
</div>

Updated Fiddle

Peter Darmis
fonte
2

Essa é praticamente uma cópia exata da resposta principal, mas, em vez de um link, é apenas a parte do código que importa, traduzida para ser IMO mais legível e fácil de entender. Algumas outras pequenas mudanças incluem o uso de cloneNode () e não a inserção de html em uma string js. Coisas pequenas, mas você pode copiar e colar como está e funcionará.

A maneira como funciona é fazer duas divs invisíveis preencherem o elemento que você está assistindo e, em seguida, colocar um gatilho em cada uma delas e definir uma posição de rolagem que levará a uma mudança de rolagem se o tamanho mudar.

Todo o crédito real é para Marc J, mas se você está apenas procurando pelo código relevante, aqui está:

    window.El = {}

    El.resizeSensorNode = undefined;
    El.initResizeNode = function() {
        var fillParent = "display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;";
        var triggerStyle = "position: absolute; left: 0; top: 0; transition: 0s;";

        var resizeSensor = El.resizeSensorNode = document.createElement("resizeSensor");
        resizeSensor.style = fillParent;

        var expandSensor = document.createElement("div");
        expandSensor.style = fillParent;
        resizeSensor.appendChild(expandSensor);

        var trigger = document.createElement("div");
        trigger.style = triggerStyle;
        expandSensor.appendChild(trigger);

        var shrinkSensor = expandSensor.cloneNode(true);
        shrinkSensor.firstChild.style = triggerStyle + " width: 200%; height: 200%";
        resizeSensor.appendChild(shrinkSensor);
    }


    El.onSizeChange = function(domNode, fn) {
        if (!domNode) return;
        if (domNode.resizeListeners) {
            domNode.resizeListeners.push(fn);
            return;
        }

        domNode.resizeListeners = [];
        domNode.resizeListeners.push(fn);

        if(El.resizeSensorNode == undefined)
            El.initResizeNode();

        domNode.resizeSensor = El.resizeSensorNode.cloneNode(true);
        domNode.appendChild(domNode.resizeSensor);

        var expand = domNode.resizeSensor.firstChild;
        var expandTrigger = expand.firstChild;
        var shrink = domNode.resizeSensor.childNodes[1];

        var reset = function() {
            expandTrigger.style.width = '100000px';
            expandTrigger.style.height = '100000px';

            expand.scrollLeft = 100000;
            expand.scrollTop = 100000;

            shrink.scrollLeft = 100000;
            shrink.scrollTop = 100000;
        };

        reset();

        var hasChanged, frameRequest, newWidth, newHeight;
        var lastWidth = domNode.offsetWidth;
        var lastHeight = domNode.offsetHeight;


        var onResized = function() {
            frameRequest = undefined;

            if (!hasChanged) return;

            lastWidth = newWidth;
            lastHeight = newHeight;

            var listeners = domNode.resizeListeners;
            for(var i = 0; listeners && i < listeners.length; i++) 
                listeners[i]();
        };

        var onScroll = function() {
            newWidth = domNode.offsetWidth;
            newHeight = domNode.offsetHeight;
            hasChanged = newWidth != lastWidth || newHeight != lastHeight;

            if (hasChanged && !frameRequest) {
                frameRequest = requestAnimationFrame(onResized);
            }

            reset();
        };


        expand.addEventListener("scroll", onScroll);
        shrink.addEventListener("scroll", onScroll);
    }
Seph Reed
fonte
1

Solução Javascript pura, mas funciona apenas se o elemento for redimensionado com o botão redimensionar css :

  1. armazenar tamanho elemento com offsetWidth e offsetHeight ;
  2. adicione um ouvinte de evento onclick neste elemento;
  3. Quando acionado, compare os valores atuais offsetWidthe offsetHeightarmazenados e, se diferente, faça o que deseja e atualize esses valores.
roipoussiere
fonte
1

Aqui está uma versão simplificada da solução por @nkron, aplicável a um único elemento (em vez de uma matriz de elementos na resposta do @ nkron, complexidade que eu não precisava).

function onResizeElem(element, callback) {    
  // Save the element we are watching
  onResizeElem.watchedElementData = {
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  };

  onResizeElem.checkForChanges = function() {
    const data = onResizeElem.watchedElementData;
    if (data.element.offsetWidth !== data.offsetWidth || data.element.offsetHeight !== data.offsetHeight) {
      data.offsetWidth = data.element.offsetWidth;
      data.offsetHeight = data.element.offsetHeight;
      data.callback();
    }
  };

  // Listen to the window resize event
  window.addEventListener('resize', onResizeElem.checkForChanges);

  // Listen to the element being checked for width and height changes
  onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
  onResizeElem.observer.observe(document.body, {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  });
}

O ouvinte e o observador de eventos podem ser removidos por:

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();
Gman
fonte
0
jQuery(document).ready( function($) {

function resizeMapDIVs() {

// check the parent value...

var size = $('#map').parent().width();



if( $size < 640 ) {

//  ...and decrease...

} else {

//  ..or increase  as necessary

}

}

resizeMapDIVs();

$(window).resize(resizeMapDIVs);

});
Fábio Zangirolami
fonte
0

usando a resposta Bharat Patil simplesmente retorne false dentro do retorno de chamada do bind para evitar o erro máximo da pilha, veja o exemplo abaixo:

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});
Coelho branco
fonte
0

Essa é uma pergunta muito antiga, mas achei que postaria minha solução para isso.

Eu tentei usar, ResizeSensorjá que todo mundo parecia ter uma queda muito grande por isso. Após a implementação, percebi que, sob o capô, a consulta do elemento exige que o elemento em questão tenha posição relativeou se absoluteaplique a ele, o que não funcionou para a minha situação.

Acabei lidando com isso com um Rxjs em intervalvez de implementações anteriores diretas setTimeoutou requestAnimationFramesemelhantes.

O legal do sabor observável de um intervalo é que você pode modificar o fluxo, mas qualquer outro observável pode ser tratado. Para mim, uma implementação básica foi suficiente, mas você pode enlouquecer e fazer todo tipo de fusão, etc.

No exemplo abaixo, estou acompanhando as alterações de largura da div interna (verde). Tem uma largura definida para 50%, mas uma largura máxima de 200px. Arrastar o controle deslizante afeta a largura da div do wrapper (cinza). Você pode ver que o observável é acionado apenas quando a largura da div interna é alterada, o que só acontece se a largura da div externa for menor que 400px.

const { interval } = rxjs;
const { distinctUntilChanged, map, filter } = rxjs.operators;


const wrapper = document.getElementById('my-wrapper');
const input = document.getElementById('width-input');




function subscribeToResize() {
  const timer = interval(100);
  const myDiv = document.getElementById('my-div');
  const widthElement = document.getElementById('width');
  const isMax = document.getElementById('is-max');
  
  /*
    NOTE: This is the important bit here 
  */
  timer
    .pipe(
      map(() => myDiv ? Math.round(myDiv.getBoundingClientRect().width) : 0),
      distinctUntilChanged(),
      // adding a takeUntil(), here as well would allow cleanup when the component is destroyed
    )
      .subscribe((width) => {        
        widthElement.innerHTML = width;
        isMax.innerHTML = width === 200 ? 'Max width' : '50% width';

      });
}

function defineRange() {
  input.min = 200;
  input.max = window.innerWidth;
  input.step = 10;
  input.value = input.max - 50;
}

function bindInputToWrapper() {
  input.addEventListener('input', (event) => {
    wrapper.style.width = `${event.target.value}px`;
  });
}

defineRange();
subscribeToResize();
bindInputToWrapper();
.inner {
  width: 50%;
  max-width: 200px;
}




/* Aesthetic styles only */

.inner {
  background: #16a085;
}

.wrapper {
  background: #ecf0f1;
  color: white;
  margin-top: 24px;
}

.content {
  padding: 12px;
}

body {
  
  font-family: sans-serif;
  font-weight: bold;
}
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

<h1>Resize Browser width</h1>

<label for="width-input">Adjust the width of the wrapper element</label>
<div>
  <input type="range" id="width-input">
</div>

<div id="my-wrapper" class="wrapper">
  <div id="my-div" class="inner">
    <div class="content">
      Width: <span id="width"></span>px
      <div id="is-max"></div>  
    </div>
  </div>
</div>

Scrimothy
fonte
-1

Window.onResizeExiste apenas na especificação, mas você sempre pode utilizar IFramepara gerar um novo Windowobjeto dentro do seu DIV.

Por favor, verifique esta resposta . Existe um novo plugin jquery pequeno , portátil e fácil de usar. Você sempre pode verificar o código-fonte para ver como é feito.

<!-- (1) include plugin script in a page -->
<script src="/src/jquery-element-onresize.js"></script>

// (2) use the detectResizing plugin to monitor changes to the element's size:
$monitoredElement.detectResizing({ onResize: monitoredElement_onResize });

// (3) write a function to react on changes:
function monitoredElement_onResize() {    
    // logic here...
}
rbtbar
fonte
Esta é uma solução altamente ineficaz se você tiver divs redimensionáveis.
suricactus
-1

Eu pensei que não poderia ser feito, mas então eu pensei sobre isso, você pode redimensionar manualmente uma div via style = "resize: both;" para fazer isso, clique nele para adicionar uma função onclick para verificar a altura e a largura do elemento e ele funcionou. Com apenas 5 linhas de javascript puro (com certeza pode ser ainda mais curto) http://codepen.io/anon/pen/eNyyVN

<div id="box" style="
                height:200px; 
                width:640px;
                background-color:#FF0066;
                resize: both;
                overflow: auto;" 
                onclick="myFunction()">
    <p id="sizeTXT" style="
                font-size: 50px;">
       WxH
    </p>
    </div>

<p>This my example demonstrates how to run a resize check on click for resizable div.</p>

<p>Try to resize the box.</p>


<script>
function myFunction() {
var boxheight = document.getElementById('box').offsetHeight;
var boxhwidth = document.getElementById('box').offsetWidth;
var txt = boxhwidth +"x"+boxheight;
document.getElementById("sizeTXT").innerHTML = txt;
}
</script>
PixelPimp
fonte
2
Isso calcula apenas quando um evento de clique é acionado, o que não faz parte do requisito da pergunta.
Rob Evans