¿Cómo detectar la dimensión de DIV cambiada?

351

Tengo el siguiente html de muestra, hay un DIV que tiene un ancho del 100%. Contiene algunos elementos. Mientras se realiza el cambio de tamaño de las ventanas, los elementos internos pueden ser reubicados y la dimensión del div puede cambiar. Estoy preguntando si es posible conectar el evento de cambio de dimensión del div. ¿y como hacer eso? Actualmente asocio la función de devolución de llamada al evento jQuery resize en el DIV de destino, sin embargo, no se genera ningún registro de consola, consulte a continuación:

Antes de cambiar el tamaño ingrese la descripción de la imagen aquí

<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
fuente
77
Esto no funcionará porque está vinculando el evento de cambio de tamaño al elemento div especificado. Pero el evento de cambio de tamaño se activará para la ventana, no para su elemento.
Fatih Acet
Podría usar setIntervalaquí como una posible solución. Siempre puede vincularse clearIntervala un clic de botón para detener el ciclo una vez que haya terminado su trabajo.
Peter Darmis
1
Desde 2020, ResizeObserver funciona en todos los principales navegadores (Chrome, Safari, Firefox, Edge) excepto IE. caniuse.com/#feat=resizeobserver
Dan

Respuestas:

264

Hay un método muy eficiente para determinar si se ha cambiado el tamaño de un elemento.

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

Esta biblioteca tiene una clase ResizeSensorque se puede usar para la detección de cambio de tamaño.
Utiliza un enfoque basado en eventos, por lo que es muy rápido y no pierde el tiempo de la CPU.

Ejemplo:

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

No use el complemento jQuery onresize, ya que se usa setTimeout()en combinación con la lectura de DOM clientHeight/ clientWidthpropiedades en un bucle para verificar los cambios.
Esto es increíblemente lento e inexacto, ya que causa un cambio de diseño .

Divulgación: estoy directamente asociado con esta biblioteca.

Marc J. Schmidt
fuente
8
@jake, ahora se implementa el soporte de IE11.
Marc J. Schmidt
15
@Aletheios deberías echar un vistazo más de cerca. requestAnimationFrame no es para la detección de dimensiones lentas, sino exactamente lo contrario: suaviza todos esos números extremos de eventos que son activados por el sensor de cambio de tamaño basado en eventos reales para ahorrar tiempo de CPU. Ver documentos actualizados en github.com/marcj/css-element-queries/blob/master/src/…
Marc J. Schmidt
66
@Aletheios Supongo que pierdes un punto: setTimeout no solo es inexacto sino lento como el infierno. Un requestAnimationFrame que verifica un booleano simple es un orden de magnitud más rápido que un setTimeout que verifica todo el tiempo con las propiedades DOM. Además de eso, setTimeout también se llama cada pocos milisegundos.
Marc J. Schmidt
99
@Orwellophile obviamente no has entendido nada. Deje de votar negativamente cuando no tenga idea de cómo funciona internamente. Nuevamente: css-element-query: utiliza un evento de cambio de tamaño real que se activa cada vez que cambia la dimensión. Como obtendría demasiados eventos (por ejemplo, arrastrar y soltar), agregó requestAnimationFrame para verificar una variable booleana simple para suavizar esos eventos desencadenados a 1 / fotograma. Complemento jquery: utiliza un setTimeout que comprueba todo el tiempo los accesorios de diseño DOM (clientHeight, etc.) donde cada comprobación es muy lenta pero debe verificarse a menudo para tener la misma funcionalidad.
Marc J. Schmidt
99
@Aletheios, @Orwellophile y cualquiera que haya sido engañado por ellos: requestAnimationFramevs setTimeoutes irrelevante, esta biblioteca no se repite . requestAnimationFramesolo se usa para eliminar la frecuencia de aceleración de las llamadas de devolución de llamada, no sondea . MutationObserver teóricamente podría usarse con un efecto similar, pero no en navegadores antiguos, a diferencia de esto. Esto es excepcionalmente inteligente.
Han Seoul-Oh
251

Un nuevo estándar para esto es la API Resize Observer, disponible en 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>

Observador de cambio de tamaño

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

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

Problema de Firefox: https://bugzil.la/1272409

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

Soporte actual: http://caniuse.com/#feat=resizeobserver

Daniel Herr
fuente
3
aún no es útil para sitios de producción, ya que solo Chrome lo admite en este momento. ¡Pero definitivamente la mejor solución aquí! por cierto, aquí hay un resumen rápido del estado de implementación: chromestatus.com/feature/5705346022637568
Philipp
8
@Philipp Hay un polyfill.
Daniel Herr
2
Parece que todavía es una característica experimental en todos los navegadores caniuse.com/#feat=resizeobserver
Francesc Rosas
55
Incluso 2 años después de esta respuesta, el soporte del navegador es sombrío: caniuse.com/#search=resizeobserver
Scrimothy
2
Funciona de maravilla en los últimos Chrome y FF.
Klemen Tušar
32

Tienes que vincular el resizeevento en elwindow objeto, no en un elemento html genérico.

Entonces podrías usar esto:

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

y dentro de la función de devolución de llamada puede verificar el nuevo ancho de su divllamada

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

Entonces, la respuesta a su pregunta es no , no puede vincular el resizeevento a un div.

Alessandro Vendruscolo
fuente
124
Esta respuesta no es lo suficientemente buena. los cambios de tamaño pueden ocurrir sin CUALQUIER cambio de tamaño de ventana. en absoluto.
vsync
99
por ejemplo, cuando tiene un elemento divisor o simplemente agrega texto u otro contenido a un elemento.
Günter Zöchbauer
@anu no es cierto, puede tener, por ejemplo, una modificación DOM a través de JavaScript, lo que hace que CSS se aplique a una nueva estructura, lo que da como resultado un diseño diferente - tamaño de cada contenedor.
Antoniossss
29

A largo plazo, podrá utilizar ResizeObserver .

new ResizeObserver(callback).observe(element);

Lamentablemente, actualmente no es compatible de forma predeterminada en muchos navegadores.

Mientras tanto, puede usar funciones como las siguientes. Dado que, la mayoría de los cambios en el tamaño del elemento vendrán del cambio de tamaño de la ventana o de cambiar algo en el DOM. Se puede escuchar el redimensionamiento de la ventana con el cambio de tamaño del evento y se puede escuchar a DOM cambia usando MutationObserver .

Aquí hay un ejemplo de una función que le devolverá la llamada cuando el tamaño del elemento proporcionado cambie como resultado de cualquiera de esos 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
fuente
1
Desafortunadamente, parece que MutationObserver no puede detectar cambios en Shadow DOM.
Ajedi32
@nkron, desafortunadamente, si usa el cambio de tamaño CSS3 , el cambio de tamaño puede ocurrir cuando el usuario cambia el tamaño manualmente. Este evento no puede ser atrapado.
Pacerier
@ Ajedi32 Sí, pero puedes usar MutationObserver dentro de ShadowDOM. Lo que quiero decir es que en lugar de mirar el bodycomo en este ejemplo, puedes mirar un elemento directamente. Eso es en realidad más eficiente y eficiente que mirar todo el cuerpo.
trusktr
@ Ajedi32 Bueno, el único problema es que si el árbol Shadow DOM está cerrado, entonces no podrás acceder a las partes internas, pero no creo que sea algo que debas hacer, y si necesitas observar un árbol cerrado como ese puede haber un problema en el diseño. Idealmente, solo debería observar sus propios elementos a los que tiene acceso. Un componente Shadow-DOM que requiere que observe su tamaño interno puede no estar diseñado correctamente. ¿Tienes un ejemplo específico? Si es así, tal vez pueda ayudar a sugerir una solución (porque también me interesa, pero todavía no tengo ningún ejemplo).
trusktr
@trusktr No tengo un MCVE en este momento, pero básicamente cualquier elemento Shadow DOM que pueda cambiar su tamaño como resultado de alguna entrada del usuario sería suficiente para desencadenar este problema. Un cuadro que se expande con información adicional al hacer clic, por ejemplo. Tenga en cuenta que estoy observando la página, no el elemento individual, porque quiero desplazarme automáticamente hacia abajo cuando el tamaño de la página aumenta, independientemente de la razón. La expansión de un elemento Shadow DOM es solo una de las muchas razones posibles por las que la página podría alargarse.
Ajedi32
24

ResizeSensor.js es parte de una gran biblioteca, pero reduje su funcionalidad a ESTO :

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

Cómo usarlo:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});
Martin Wantke
fuente
Esto es lo que hacen los gráficos js.
Antoniossss
Gracias por comprimir eso. Voy a probarlo :)
Tony K.
Falta algo en esta expresiónparseInt( getComputedStyle(element) )
GetFree
2
Estoy confundido sobre cómo es "let zIndex = parseInt (getComputedStyle (element));" ¿válido? Supongo que quiso decir: "let zIndex = parseInt (getComputedStyle (element) .zIndex);
Ryan Badour el
1
La solución / código anterior no detecta todos los eventos de cambio de tamaño (por ejemplo, si un contenedor cambia de tamaño a fijo, no detecta el cambio de tamaño para eventos secundarios. Consulte jsfiddle.net/8md2rfsy/1 ). La respuesta aceptada funciona (descomenta las líneas respectivas).
nuevoBee
21

¡NO recomiendo setTimeout()hackear ya que ralentiza el rendimiento! En su lugar, puede usar observadores de mutación DOM para escuchar el cambio de tamaño 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>

Aquí está el violín
Intenta cambiar el tamaño del div.


Puede ajustar aún más su método en el debouncemétodo para mejorar la eficiencia. debounceactivará su método cada x milisegundos en lugar de activar cada milisegundo que se cambia el tamaño del DIV.

JerryGoyal
fuente
99
El único problema con este es que no informa un cambio a menos que una mutación realmente le ocurra al elemento. Si el elemento cambia de tamaño debido a la adición de otros elementos, esto no funcionará.
Tony K.
Estoy de acuerdo con @TonyK., Este es mi único problema con MutationObserver y ahora estoy buscando una biblioteca de cambio de tamaño de elemento
Murhaf Sousli
@JerryGoyal No funciona cuando el div contiene la etiqueta <img>. En primera instancia, la imagen no se carga y el tamaño div se establece en 0 y después de la carga se cambia el tamaño div, pero no se activa el observador
Santhosh
15

La mejor solución sería utilizar las llamadas consultas de elementos . Sin embargo, no son estándar, no existe una especificación, y la única opción es utilizar uno de los polyfills / bibliotecas disponibles, si desea seguir este camino.

La idea detrás de las consultas de elementos es permitir que un determinado contenedor de la página responda al espacio que se le proporciona. Esto permitirá escribir un componente una vez y luego soltarlo en cualquier lugar de la página, mientras ajusta su contenido a su tamaño actual. No importa el tamaño de la ventana. Esta es la primera diferencia que vemos entre las consultas de elementos y las consultas de medios. Todos esperan que en algún momento se cree una especificación que estandarice las consultas de elementos (o algo que logre el mismo objetivo) y las haga nativas, limpias, simples y robustas. La mayoría de la gente está de acuerdo en que las consultas de medios son bastante limitadas y no ayudan para el diseño modular y la verdadera capacidad de respuesta.

Hay algunos polyfills / bibliotecas que resuelven el problema de diferentes maneras (sin embargo, podrían llamarse soluciones alternativas en lugar de soluciones):

He visto otras soluciones a problemas similares propuestos. Por lo general, usan temporizadores o el tamaño de ventana / ventana debajo del capó, lo que no es una solución real. Además, creo que idealmente esto debería resolverse principalmente en CSS, y no en javascript o html.

Stan
fuente
+1 para consultas de elementos, pero no tengo esperanzas de verlas pronto. Ni siquiera hay un borrador de especificaciones en este punto AFAIK ... ¿tal vez una de las partes interesadas deberíamos armar uno y enviarlo?
Rob Evans
1
Esa es una buena idea, por supuesto. Tomará mucho tiempo llegar a una versión final, se debe llamar mucho la atención. Diseñar esto de una buena manera no me parece trivial. Compatibilidad entre navegadores, dependencias circulares, depuración, legibilidad y mantenimiento, etc. Así que comencemos lo antes posible :)
Stan
@Stan, creo que esta respuesta puede ser mejor agregando más detalles sobre de qué se trata Element Query.
Pacerier
15

Encontré que esta biblioteca funcionaba cuando la solución de MarcJ no lo hizo:

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

Es muy ligero y detecta incluso los cambios de tamaño naturales a través de CSS o simplemente la carga / representación HTML.

Ejemplo de código (tomado del enlace):

<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
fuente
Eso es todo. 147 líneas, utiliza eventos de desplazamiento. Lea este código si desea la respuesta completa y verdadera sobre cómo detectar mejor los cambios de dimensión div. Sugerencia: no es "solo usar esta biblioteca".
Seph Reed
1
La gente debería echar un vistazo a este problema antes de probar esta biblioteca.
Louis
13

Echa un vistazo a este http://benalman.com/code/projects/jquery-resize/examples/resize/

Tiene varios ejemplos. Intente cambiar el tamaño de su ventana y vea cómo se ajustan los elementos dentro de los elementos del contenedor.

Ejemplo con js fiddle para explicar cómo hacer que funcione.
Echa un vistazo a este violín http://jsfiddle.net/sgsqJ/4/

En ese evento resize () está vinculado a elementos que tienen la clase "test" y también al objeto de ventana y en el cambio de tamaño de devolución de llamada del objeto de ventana $ ('. Test'). Se llama a resize ().

p.ej

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

$(window).resize(function(){
   $('#test_div').resize();
});
Bharat Patil
fuente
Interesante. Ese jsfiddle bloquea constantemente Chrome con el inspector está abierto y hago clic en el enlace "Agregar más texto". Firefox arroja errores de "demasiada recursividad".
EricP
3
No utilice el complemento de cambio de tamaño de jQuery. Es realmente lento y no es preciso también. Vea mi respuesta para obtener una mejor solución.
Marc J. Schmidt
24
Esto NO detecta directamente los cambios de dimensión. es solo un subproducto de un detector de eventos de cambio de tamaño. Un cambio de dimensión puede ocurrir de muchas otras maneras.
vsync
44
¿Qué pasa si el cambio de tamaño del div es por cambio de estilo o dom y no por cambio de tamaño de ventana?
asombro
9

Puede usar iframeo objectusar contentWindowo contentDocumentcambiar el tamaño. Sin setIntervalosetTimeout

Los pasos:

  1. Establezca la posición de su elemento en relative
  2. Añadir dentro de un IFRAME oculto absoluto transparente
  3. Escucha IFRAME.contentWindow- onresizeevento

Un ejemplo 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>

El 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')
})

Ejecutando ejemplo

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


Ver más:

Aminadav Glickshtein
fuente
1
Una nota para aquellos que no usan jquery, IFRAME.contentWindowno está disponible hasta que el onloadevento se active en el iframe. Además, es posible que desee agregar el estilo visibility:hidden;, ya que el iframe puede bloquear la entrada del mouse a los elementos detrás de él (parece estar "flotando" en IE al menos).
James Wilkins
3
Aunque esto funciona, es una solución pesada con la sobrecarga de crear un contexto de navegación completamente nuevo solo para observar el cambio de tamaño. Además, en algunos casos no es ideal o factible cambiar la displaypropiedad del elemento.
trusktr
acordado, esta es una solución terrible como se indicó anteriormente
29er
¿Cómo escribió una solución tan terrible?
Aminadav Glickshtein
Este método funciona bien con reproductores de video y audio que necesitan cambiar el tamaño del contenido dinámico. Estoy usando este método para cambiar el tamaño de la salida de wavesurfer.js.
David Clews
8

Solo el objeto de ventana genera un evento de "cambio de tamaño". La única forma en que sé hacer lo que quieres hacer es ejecutar un temporizador de intervalos que verifique periódicamente el tamaño.

Puntiagudo
fuente
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
fuente
7

Sorprendentemente tan antiguo como es este problema, sigue siendo un problema en la mayoría de los navegadores.

Como otros han dicho, Chrome 64+ ahora viene con Resize Observes de forma nativa, sin embargo, la especificación aún se está ajustando y Chrome está actualmente (a partir del 2019-01-29) detrás de la última edición de la especificación .

He visto un par de buenos rellenos ResizeObserver en la naturaleza, sin embargo, algunos no siguen la especificación de cerca y otros tienen algunos problemas de cálculo.

Necesitaba desesperadamente este comportamiento para crear algunos componentes web receptivos que pudieran usarse en cualquier aplicación. Para que funcionen bien, necesitan conocer sus dimensiones en todo momento, por lo que ResizeObservers sonaba ideal y decidí crear un polyfill que siguiera la especificación lo más cerca posible.

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

Demostración: https://codesandbox.io/s/myqzvpmmy9

Trem
fuente
Definitivamente, esta es la respuesta perfecta para cualquiera que tenga que ver con la compatibilidad del navegador IE11 +.
ekfuhrmann
3

Usando Clay.js ( https://github.com/zzarcon/clay ) es bastante simple detectar cambios en el tamaño del elemento:

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

el.on('resize', function(size) {
    console.log(size.height, size.width);
});
Zzarcon
fuente
77
Proporcione la divulgación adecuada dado que es su biblioteca.
jhpratt GOFUNDME RELICENSING
Esto funcionó para mí, donde ResizeSensor no lo hace, rompe mi estilo modal. Gracias Zzarcon :)
Máxima Alekz
3

Esta publicación de blog me ayudó a detectar de manera eficiente los cambios de tamaño en los elementos DOM.

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

Cómo usar este código ...

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

Código empaquetado utilizado por el ejemplo ...

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 es un espacio de nombres / objeto que uso para organizar funciones reutilizables. Siéntase libre de buscar y reemplazar el nombre con cualquier cosa que desee.

Ben Gripka
fuente
3

Mi complemento jQuery habilita el evento "redimensionar" en todos los elementos, no solo en el window.

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 
Dustin Poissant
fuente
1
Su enlace apuntaba a una ubicación que ya no existe. Busqué el nombre del complemento y encontré una página que corresponde a su descripción. Como pareces ser el autor del complemento, también he editado el idioma de tu respuesta para hacer explícito que este es tu trabajo. Las reglas de este sitio son tales que cuando escribe respuestas, recomienda usar algo que haya desarrollado, debe hacer explícita la relación.
Louis
Esta no es una gran solución porque ejecuta alguna función en setTimer una y otra vez, lo que significa que el navegador está constantemente quemando la CPU, incluso si no sucede nada. Los propietarios de computadoras portátiles y teléfonos celulares se benefician de una solución que usa eventos del navegador solo cuando hay alguna acción, como usar el evento onScroll.
Roman Zenka
2

Puede probar el código en el siguiente fragmento, que cubre sus necesidades utilizando JavaScript simple. ( ejecute el fragmento de código y haga clic en el enlace de la página completa para activar la alerta de que el div cambia de tamaño si desea probarlo ).

Basado en el hecho de que esto es setIntervalde 100 milisegundos, me atrevería a decir que mi PC no encontró mucha CPU hambrienta. (Se utilizó el 0,1% de la CPU como total para todas las pestañas abiertas en Chrome en el momento de la prueba). Pero, de nuevo, esto es solo para un div, si desea hacer esto para una gran cantidad de elementos, entonces sí podría tener mucha CPU.

Siempre puede usar un evento de clic para detener el rastreo div- resize de todos modos.

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>

Puedes comprobar el violín también

ACTUALIZAR

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>

Fiddle actualizado

Peter Darmis
fuente
2

Esta es más o menos una copia exacta de la respuesta principal, pero en lugar de un enlace, lo que importa es solo la parte del código, traducida para que sea IMO más legible y más fácil de entender. Algunos otros pequeños cambios incluyen el uso de cloneNode () y no poner html en una cadena js. Cosas pequeñas, pero puedes copiar y pegar esto como está y funcionará.

La forma en que funciona es haciendo que dos divisiones invisibles llenen el elemento que está viendo, y luego poniendo un gatillo en cada uno, y estableciendo una posición de desplazamiento que conducirá a activar un cambio de desplazamiento si cambia el tamaño.

Todo el crédito real va a Marc J, pero si solo está buscando el código relevante, aquí 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
fuente
1

Solución Javascript pura, pero solo funciona si el elemento se redimensiona con el botón de cambio de tamaño CSS :

  1. almacenar el tamaño del elemento con offsetWidth y offsetHeight ;
  2. agregue un detector de eventos onclick en este elemento;
  3. cuando se active, compare los valores actuales offsetWidthy los offsetHeightvalores almacenados, y si es diferente, haga lo que quiera y actualice estos valores.
roipoussiere
fuente
1

Aquí hay una versión simplificada de la solución de @nkron, aplicable a un solo elemento (en lugar de una matriz de elementos en la respuesta de @ nkron, complejidad que no necesitaba).

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

El oyente y el observador del evento pueden eliminarse mediante:

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();
Gman
fuente
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
fuente
0

usando la respuesta de Bharat Patil, simplemente devuelva falso dentro de la devolución de llamada de su enlace para evitar el error de pila máxima, vea el siguiente ejemplo:

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});
conejo blanco
fuente
0

Esta es una pregunta muy antigua, pero pensé que publicaría mi solución a esto.

Traté de usarlo ResizeSensorya que todo el mundo parecía estar bastante enamorado de él. Sin embargo, después de implementar, me di cuenta de que, bajo el capó, la consulta de elementos requiere que el elemento en cuestión tenga una posición relativeo se le absoluteaplique, lo que no funcionó para mi situación.

Terminé manejando esto con un Rxjs en intervallugar de una implementación anterior directa setTimeouto requestAnimationFramesimilar.

Lo bueno del sabor observable de un intervalo es que puedes modificar la transmisión, sin embargo, cualquier otro observable puede ser manejado. Para mí, una implementación básica era suficiente, pero podría volverse loco y hacer todo tipo de fusiones, etc.

En el siguiente ejemplo, estoy rastreando los cambios de ancho del div (verde) interno. Tiene un ancho establecido en 50%, pero un ancho máximo de 200 px. Al arrastrar el control deslizante, se afecta el ancho del contenedor (gris) div. Puedes ver que lo observable solo se dispara cuando cambia el ancho del div interno, lo que solo sucede si el ancho del div externo es 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
fuente
-1

Solo Window.onResizeexiste en la especificación, pero siempre puede utilizarlo IFramepara generar un nuevo Windowobjeto dentro de su DIV.

Por favor revisa esta respuesta . Hay un nuevo pequeño complemento jquery , que es portátil y fácil de usar. Siempre puede verificar el código fuente para ver cómo se hace.

<!-- (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
fuente
Esta es una solución altamente ineficaz si tiene divs redimensionables.
suricactus
-1

pensé que no se podía hacer, pero luego lo pensé, puedes cambiar el tamaño manualmente de un div a través de style = "resize: both;" para hacer eso, debe hacer clic en él, por lo que agregó una función onclick para verificar la altura y el ancho del elemento y funcionó. Con solo 5 líneas de javascript puro (seguro que podría ser aún más corto) 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
fuente
2
Esto solo se calcula cuando se activa un evento de clic que no es parte del requisito de la pregunta.
Rob Evans