Cambiar el tamaño del elemento div

80

jQuery tiene el resize()evento -, pero solo funciona con window.

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

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

P.ej

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

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

¿Existe alguna solución para hacer esto?

TJR
fuente
2
Los eventos de cambio de tamaño solo se activan en objetos de ventana (¿y quizás iframes?)
BiAiB
3
eche un vistazo a esta página - benalman.com/code/projects/jquery-resize/examples/resize
Elen
Esto podría ayudar: resizeObserver. developer.mozilla.org/en-US/docs/Web/API/ResizeObserver . Compatible con Chrome 64, Firefox 69 ...
capitán puget

Respuestas:

35

DIVno dispara un resizeevento, por lo que no podrá hacer exactamente lo que ha codificado, pero podría considerar monitorear las propiedades del DOM .

Si en realidad está trabajando con algo como resizables, y esa es la única forma de que un div cambie de tamaño, entonces su complemento de cambio de tamaño probablemente implementará una devolución de llamada propia.

David Hedlund
fuente
Puede activar el evento de cambio de tamaño de la ventana con $ (ventana) .trigger ("resize");
Laurent
32

Solo estaba interesado en un disparador cuando se cambiaba el ancho de un elemento (no me importa la altura), así que creé un evento jquery que hace exactamente eso, usando un 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);
      };
  }
}

Requiere el siguiente CSS:

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

Puedes verlo en acción aquí widthChanged violín

Panos Theof
fuente
Esta es la respuesta correcta. Adjuntar el evento a la ventana de un iframe es mucho menos complicado que un intervalo.
Kevin Beal
1
¡Esto es perfecto! Hice el mío completamente basado 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);
sroskelley
Esto es pura genialidad.
Thomas
Estoy a punto de usarlo, pero me pregunto: ¿cuál es el papel del temporizador y el setTimeout? ¿Es como un "rebote" / acelerador para evitar que se detecten demasiados cambios de tamaño cuando el usuario cambia el tamaño del elemento?
Mathieu
Sí, es para evitar invocar demasiadas veces el disparador "widthChanged"
Panos Theof
22
// 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));
Akram Kamal Qassas
fuente
7

Creé el complemento jquery jquery.resize , use resizeObserver si es compatible o una solución basada en el evento de desplazamiento marcj / css-element-queries , sin setTimeout / setInterval.

Usas solo

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

o como complemento de cambio de tamaño

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

Creé esto para jQuery Terminal y lo extraje en un repositorio separado y un paquete npm, pero mientras tanto cambié a iframe oculto porque tuve problemas con el cambio de tamaño si el elemento estaba dentro de iframe. Puedo actualizar el complemento en consecuencia. Puede ver el complemento de cambio de tamaño basado en iframe en el código fuente de jQuery Terminal .

EDITAR : la nueva versión usa iframe y cambia el tamaño de su objeto de ventana porque las soluciones anteriores no funcionaban cuando la página estaba dentro de iframe.

EDIT2 : debido a que el iframe de respaldo no puede usarlo con controles de formulario o imágenes, debe agregarlo al elemento contenedor.

EDIT3: hay una mejor solución usando resizeObserver polyfill que usa el observador de mutación (si resizeObserver no es compatible) y funciona incluso en IE. También tiene mecanografía de TypeScript.

jcubic
fuente
Fue una gran idea. Buen trabajo, de verdad.
Marco Luzzara
6

que hay de 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);

Por cierto, le sugiero que agregue una identificación al div y cambie $ ("div") a $ ("# yourid"), será más rápido y no se romperá cuando luego agregue otros divs

Gavriel
fuente
Por supuesto, fue solo un ejemplo, por supuesto que uso identificaciones y clases para seleccionar mis elementos. Me gusta tu idea, ¡creo que funcionaría! Muchas gracias. Lo intentaré en unos minutos y daré un comentario.
TJR
Esto monitorea el DIV en busca de cambios de tamaño cada vez resizeque se dispara el evento de la ventana . Es muy posible que el tamaño del div cambie sin ser seguido inmediatamente por un cambio de tamaño de la ventana, en cuyo caso la /* what ever */parte no sería evaluada.
David Hedlund
¡Correcto! Y este es el problema de 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 de otras formas, el ejemplo funcionará bien, acabo de probarlo.
TJR
@Timo: $(window).resizeescucha el acto de cambiar físicamente el tamaño de la ventana del navegador, por ejemplo, arrastrando la esquina inferior derecha. No hay eventos DOM que desencadenan este evento, overflow:hiddeno no. Esta respuesta no resuelve su problema. Tendría más sentido ejecutar este código en un temporizador que adjuntarlo a un detector de eventos aleatorio que probablemente nunca se activará. Sería mejor aún si pudiera usar el monitoreo de propiedades DOM y recurrir a un temporizador (o generar manualmente algún evento en los lugares donde el tamaño de div puede cambiar).
David Hedlund
código agregado para setInterval. Necesita ajustarlo, porque 1000ms puede ser demasiado para usted, por otro lado, un número demasiado bajo puede matar fácilmente su CPU. Si sabe que no necesita escuchar más, llame a: clearInterval (timer)!
Gavriel
5

Hay un complemento realmente agradable, fácil de usar y liviano (utiliza eventos nativos del navegador para la detección) para JavaScript básico y para jQuery que se lanzó este año. Funciona perfectamente:

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

DrCord
fuente
1
dijiste que no sondea constantemente, pero lo hace, usa requestAnimationFrame: github.com/sdecima/javascript-detect-element-resize/blob/master/…
Muhammad Umer
1
Interesante: el proyecto de GitHub al que se hace referencia se inspiró en esta publicación de blog: backalleycoder.com/2013/03/18/… Pero el código de la publicación se cambió significativamente más tarde, mientras que el proyecto de GitHub parece utilizar el enfoque anterior. Por lo tanto, vale la pena echar un vistazo a ambos antes de decidir qué usar.
CF
2

Solo se admite la ventana, sí, pero puede usar un complemento para ello: http://benalman.com/projects/jquery-resize-plugin/

Nielsen Ramon
fuente
1
No. Esto es exactamente lo que OP intentó y señaló que no funciona.
David Hedlund
esto usa setTimeout, que puede ser bastante costoso si lo usa varias veces.
jcubic
0

Para una integración de Google Maps, estaba buscando una forma de detectar cuándo un div ha cambiado de tamaño. Dado que los mapas de Google siempre requieren las dimensiones adecuadas, por ejemplo, ancho y alto, para poder renderizarse correctamente.

La solución que se me ocurrió es una delegación de un evento, en mi caso un clic de 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.mapen 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) a un evento (click ).

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

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

¡Espero que ayude a cualquiera!

Tim Vermaelen
fuente
0

Simplemente pruebe esta función (puede que no solo funcione 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);
}

Puedes usarlo así

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 usar un observador más progresivo (puede funcionar para cualquier objeto, no solo para 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);
    }

Solo inténtalo:

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

Registrará 'cambiado' cada vez que cambie b, a.foo o a.ext directamente

KaMeHb
fuente
setIntervalpuede resultar bastante caro, ya que sigue intentando cambiar el tamaño
ton
@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 cambia de tamaño. : / ¿O te preocupa el rendimiento? En los navegadores más recientes, funciona perfectamente incluso en sitios "pesados"
KaMeHb
Si agrega un simple console.logjusto antes del $.each, verá que se imprime cada 100ms, como lo configuró en elinterval
ton
@ton: Me entendiste mal. Sé bien cómo setIntervalfunciona. Es como un correo electrónico "vivo": hace ping constantemente al servidor. Lo sé. ¿Y qué? ¿Actuación? Lea mi comentario arriba. ¿Preocupado por algo más? Escríbeme, amigo mío.
KaMeHb
0

Puede cambiar su texto, contenido o atributo según el tamaño de la pantalla: HTML:

<p class="change">Frequently Asked Questions (FAQ)</p>
<p class="change">Frequently Asked Questions </p>

Javascript:

<script>
const changeText = document.querySelector('.change');
function resize() {
  if((window.innerWidth<500)&&(changeText.textContent="Frequently Asked Questions (FAQ)")){
    changeText.textContent="FAQ";
  } else {
    changeText.textContent="Frequently Asked Questions (FAQ)";
  }
}
window.onresize = resize;
</script>
Amranur Rahman
fuente
-2

Si solo desea cambiar el tamaño del div en sí, debe especificarlo en estilo css. Necesita agregar desbordamiento y cambiar el tamaño de la propiedad .

A continuación se muestra mi fragmento de código

#div1 {
        width: 90%;
        height: 350px;
        padding: 10px;
        border: 1px solid #aaaaaa;
        overflow: auto;
        resize: both;
    }

<div id="div1">

</div>
Dillip Kumar Nayak
fuente
Esta respuesta no se aplica a la publicación original. La discusión amplia aquí se trata de escuchar los cambios en el tamaño de un elemento (y realizar una acción después), no de establecer el tamaño del elemento.
MarsAndBack