2012-04-10 33 views
59

jQuery tiene el resize() - evento, pero solo funciona con la ventana.Cambiar el tamaño del elemento div

jQuery(window).resize(function() { /* What ever */ }); 

¡Esto funciona bien! Pero cuando quiero agregar el evento a un elemento div, no funciona.

E.g.

jQuery('div').resize(function() { /* What ever */ }); 

Quiero iniciar una devolución de llamada cuando el tamaño de un elemento div ha cambiado. No quiero iniciar un tamaño variable - evento - solo un evento para verificar si el tamaño de un elemento div - ha cambiado.

¿Hay alguna solución para hacer esto?

+2

los eventos de cambio de tamaño solo se activan en objetos de ventana (y ¿iframes quizás?). – BiAiB

+3

echa un vistazo a esta página - http://benalman.com/code/projects/jquery-resize/examples/resize/ – Elen

Respuesta

2

Sólo ventana está soportada Sí, pero se podía utilizar un plugin para ello: http://benalman.com/projects/jquery-resize-plugin/

+1

No. esto es exactamente lo que OP intentó, y señaló que no funciona. –

+1

¡Leí mal la actualización para corregir la respuesta! –

+0

¡Funciona en mi caso! : D – phlegx

26

DIV no se dispara un evento resize, por lo que no será capaz de hacer exactamente lo que usted ha codificado, pero se puede mira en monitoring DOM properties.

Si realmente está trabajando con algo así como resizables, y esa es la única forma en que un div cambia de tamaño, entonces su plugin de tamaño probablemente implementará una devolución de llamada propia.

6

qué pasa con esto:

divH = divW = 0; 
jQuery(document).ready(function(){ 
    divW = jQuery("div").width(); 
    divH = jQuery("div").height(); 
}); 
function checkResize(){ 
    var w = jQuery("div").width(); 
    var h = jQuery("div").height(); 
    if (w != divW || h != divH) { 
     /*what ever*/ 
     divH = h; 
     divW = w; 
    } 
} 
jQuery(window).resize(checkResize); 
var timer = setInterval(checkResize, 1000); 

cierto os sugiero agregar un id al div y cambiar el $ ("div") a $ ("# yourid"), que va a ser más rápido y no se romperá cuando más tarde agregue otros divs

+0

Por supuesto, fue solo un ejemplo; por supuesto, uso id's y clases para seleccionar mis elementos. Me gusta tu idea, ¡creo que funcionaría! Muchas gracias. No lo intentaré en unos minutos y daré tu opinión. – TJR

+0

Esto monitorea el DIV para cambios de tamaño cada vez que se activa el evento 'resize' de la ventana. Es bastante concebible que el tamaño del div cambie sin ser inmediatamente seguido por un cambio de tamaño de la ventana, en cuyo caso la parte '/ * what ever * /' no se evaluaría. –

+0

¡Correcto! Y este es el problema en mi proyecto. El elemento div está en una envoltura externa que tiene el atributo css Overflow: hidden, por lo que la ventana no cambia el tamaño. Pero en otras formas, el ejemplo funcionará bien, acabo de probarlo. – TJR

0

Para una integración de google maps que estaba buscando una manera de detectar cuando un div ha cambiado de tamaño. Dado que los mapas de Google siempre requieren las dimensiones adecuadas, p. ancho y alto para renderizar correctamente.

La solución que se me ocurrió es la delegación de un evento, en mi caso, un clic en la pestaña. Esto podría ser un cambio de tamaño de ventana, por supuesto, la idea sigue siendo la misma:

if (parent.is(':visible')) { 
    w = parent.outerWidth(false); 
    h = w * mapRatio /*9/16*/; 
    this.map.css({ width: w, height: h }); 
} else { 
    this.map.closest('.tab').one('click', function() { 
     this.activate(); 
    }.bind(this)); 
} 

this.map en este caso es mi mapa div. Dado que mi padre es invisible en la carga, el ancho y la altura calculados son 0 o no coinciden. Al usar .bind(this) puedo delegar la ejecución del script (this.activate) en un evento (click).

Ahora estoy seguro de que lo mismo aplica para los eventos de cambio de tamaño.

$(window).one('resize', function() { 
    this.div.css({ /*whatever*/ }); 
}.bind(this)); 

Espero que ayude a alguien!

3

Hay un plugin muy agradable, fácil de usar y liviano (usa exploradores nativos para detección) tanto para JavaScript básico como para jQuery que se lanzó este año. Se lleva a cabo a la perfección:

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

+1

dijiste que no sondea constantemente, pero lo hace, utiliza requestAnimationFrame: https://github.com/sdecima/javascript-detect- element-resize/blob/master/detect-element-resize.js –

+0

Interesante: el proyecto GitHub al que se hace referencia se inspiró en esta publicación del blog: http: //www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/Pero el código en la publicación se modificó significativamente más tarde, mientras que el proyecto GitHub parece utilizar el enfoque anterior. Por lo tanto, vale la pena echar un vistazo a ambos antes de decidir qué usar. –

24

sólo estaba interesado por un gatillo cuando la anchura de un elemento se ha cambiado (cuidado que don' sobre la altura), por lo que creó un evento jQuery que hace exactamente eso, utilizando una elemento iframe invisible.

$.event.special.widthChanged = { 
    remove: function() { 
     $(this).children('iframe.width-changed').remove(); 
    }, 
    add: function() { 
     var elm = $(this); 
     var iframe = elm.children('iframe.width-changed'); 
     if (!iframe.length) { 
      iframe = $('<iframe/>').addClass('width-changed').prependTo(this); 
     } 
     var oldWidth = elm.width(); 
     function elmResized() { 
      var width = elm.width(); 
      if (oldWidth != width) { 
       elm.trigger('widthChanged', [width, oldWidth]); 
       oldWidth = width; 
      } 
     } 

     var timer = 0; 
     var ielm = iframe[0]; 
     (ielm.contentWindow || ielm).onresize = function() { 
      clearTimeout(timer); 
      timer = setTimeout(elmResized, 20); 
     }; 
    } 
} 

Se requiere el siguiente CSS:

iframe.width-changed { 
    width: 100%; 
    display: block; 
    border: 0; 
    height: 0; 
    margin: 0; 
} 

Se puede ver en acción aquí widthChanged fiddle

+0

Esta es la respuesta correcta. Adjuntar el evento a la ventana de un iframe es mucho menos hacky que un intervalo. –

+0

¡Esto es perfecto! Hice la mía completamente basada en js agregando la hoja de estilo dinámicamente: 'var ss = document.createElement ('style'); ss.type = "text/css"; ss.innerHTML = "iframe.width-changed {width: 100%; display: block; border: 0; height: 0; margin: 0;}"; document.body.appendChild (ss); ' – runfaj

+0

Esto es puro genio. – Thomas

12
// this is a Jquery plugin function that fires an event when the size of an element is changed 
// usage: $().sizeChanged(function(){}) 

(function ($) { 

$.fn.sizeChanged = function (handleFunction) { 
    var element = this; 
    var lastWidth = element.width(); 
    var lastHeight = element.height(); 

    setInterval(function() { 
     if (lastWidth === element.width()&&lastHeight === element.height()) 
      return; 
     if (typeof (handleFunction) == 'function') { 
      handleFunction({ width: lastWidth, height: lastHeight }, 
          { width: element.width(), height: element.height() }); 
      lastWidth = element.width(); 
      lastHeight = element.height(); 
     } 
    }, 100); 


    return element; 
}; 

}(jQuery)); 
0

Sólo trate de esta func (que puede trabajar no sólo para divs):

function resized(elem, func = function(){}, args = []){ 
    elem = jQuery(elem); 
    func = func.bind(elem); 
    var h = -1, w = -1; 
    setInterval(function(){ 
     if (elem.height() != h || elem.width() != w){ 
      h = elem.height(); 
      w = elem.width(); 
      func.apply(null, args); 
     } 
    }, 100); 
} 

Se puede utilizar de esta manera

resized(/*element*/ '.advs-columns-main > div > div', /*callback*/ function(a){ 
    console.log(a); 
    console.log(this); //for accessing the jQuery element you passed 
}, /*callback arguments in array*/ ['I\'m the first arg named "a"!']); 

ACTUALIZACIÓN: También puede utilizar observador más progresivo (que puede funcionar para cualquier objeto, no sólo los elementos DOM):

function changed(elem, propsToBeChanged, func = function(){}, args = [], interval = 100){ 
     func = func.bind(elem); 
     var currentVal = {call: {}, std: {}}; 
     $.each(propsToBeChanged, (property, needCall)=>{ 
      needCall = needCall ? 'call' : 'std'; 
      currentVal[needCall][property] = new Boolean(); // is a minimal and unique value, its equivalent comparsion with each other will always return false 
     }); 
     setInterval(function(){ 
      $.each(propsToBeChanged, (property, needCall)=>{ 
       try{ 
        var currVal = needCall ? elem[property]() : elem[property]; 
       } catch (e){ // elem[property] is not a function anymore 
        var currVal = elem[property]; 
        needCall = false; 
        propsToBeChanged[property] = false; 
       } 
       needCall = needCall ? 'call' : 'std'; 
       if (currVal !== currentVal[needCall][property]){ 
        currentVal[needCall][property] = currVal; 
        func.apply(null, args); 
       } 
      }); 
     }, interval); 
    } 

Haga la prueba :

var b = '2', 
    a = {foo: 'bar', ext:()=>{return b}}; 
changed(a, { 
// prop name || do eval like a function? 
    foo:  false, 
    ext:  true 
},()=>{console.log('changed')}) 

se registrará 'cambiado' cada vez que se cambia b, a.foo o a.ext directamente

+0

'setInterval' puede ser bastante caro, ya que sigue intentando cambiar el tamaño – ton

+0

@ton: Creo que no tienes toda la razón. Esto ocurre solo en el caso de intentar cambiar el tamaño de un elemento mientras se redimensiona. :/¿O te preocupa el rendimiento? En los últimos navegadores funciona perfectamente incluso en sitios "pesados" – KaMeHb

+0

Si agrega un simple 'console.log' justo antes del' $ .each', lo verá imprimir cada '100ms', como lo ha configurado en el 'intervalo' – ton

Cuestiones relacionadas