Evento de cambio de tamaño de la ventana de JavaScript

Respuestas:

640

jQuery solo está envolviendo el resizeevento DOM estándar , por ejemplo.

window.onresize = function(event) {
    ...
};

jQuery puede hacer algo de trabajo para asegurarse de que el evento de cambio de tamaño se active de manera consistente en todos los navegadores, pero no estoy seguro de si alguno de los navegadores difiere, pero le animo a que pruebe en Firefox, Safari e IE.

olliej
fuente
226
Un problema potencial con este método es que está anulando el evento y, por lo tanto, no puede adjuntar varias acciones a un evento. El combo addEventListener / attachEvent es la mejor manera de hacer que su JavaScript sea compatible con cualquier otro script que se esté ejecutando en la página.
MyItchyChin
44
var onresize = window.onresize; window.onresize = function (event) {if (typeof onresize === 'function') onresize (); / ** ... * /}
SubOne
230
window.addEventListener('resize', function(){}, true);
WebWanderer
16
@SubOne es un ejemplo perfecto de cómo uno nunca debería hacerlo.
Eugene Pankov
28
ECMAScript 6 : window.onresize = () => { /* code */ };o mejor:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman
561

En primer lugar, sé que el addEventListenermétodo se ha mencionado en los comentarios anteriores, pero no vi ningún código. Como es el enfoque preferido, aquí está:

window.addEventListener('resize', function(event){
  // do stuff here
});

Aquí hay una muestra de trabajo .

Jondlm
fuente
63
Esta es la respuesta más directa.
jacoviza
77
Suena como la mejor respuesta porque no estás sobrescribiendo el evento window.onresize :-)
James Harrington
27
Muchas personas agregan oyentes de eventos anónimos como lo hace en este ejemplo, pero no es realmente una buena práctica, porque este enfoque hace que sea imposible eliminarlos posteriormente. Esto solía ser un problema porque las páginas web eran de corta duración de todos modos, pero en la actualidad de AJAX y RIA y SPA se está convirtiendo en uno. Necesitamos una forma de administrar el ciclo de vida de los oyentes de eventos. Por lo tanto, sería mejor factorizar la función de escucha en una función separada para que pueda eliminarse más tarde con removeEventListener.
Stijn de Witt
66
¿Por qué no pueden todos responder así sin toda la pelusa
Quemeful
2
Creo que hay una verdad tanto en las respuestas de Stijn de Witt como de las quemeful aquí. A veces te importa eliminar oyentes de eventos, pero en el caso de que no lo hagas, agregar todo ese código extra como en el ejemplo anterior es innecesario y puede tanto hincharse como menos legibilidad. En mi opinión, si no imagina una razón para eliminar al oyente, este enfoque es la mejor solución. Siempre puede reescribirlo más tarde si es necesario. En mi experiencia, estas necesidades solo surgen en situaciones específicas.
cazort
524

Nunca anule la función window.onresize.

En su lugar, cree una función para agregar un escucha de eventos al objeto o elemento. Esto comprueba y en caso de que los oyentes no funcionen, luego anula la función del objeto como último recurso. Este es el método preferido utilizado en bibliotecas como jQuery.

object: el elemento u objeto de ventana
type: cambiar el tamaño, desplazarse (tipo de evento)
callback: la referencia de función

var addEvent = function(object, type, callback) {
    if (object == null || typeof(object) == 'undefined') return;
    if (object.addEventListener) {
        object.addEventListener(type, callback, false);
    } else if (object.attachEvent) {
        object.attachEvent("on" + type, callback);
    } else {
        object["on"+type] = callback;
    }
};

Entonces el uso es así:

addEvent(window, "resize", function_reference);

o con una función anónima:

addEvent(window, "resize", function(event) {
  console.log('resized');
});
Alex V
fuente
100
Esta debería haber sido la respuesta aceptada. Anular onresize es solo una mala práctica.
Tiberiu-Ionuț Stan
8
¿Qué pasa con todos los cheques nulos adicionales? tratando de trabajar en IE 4.5 o algo así?
FlavorScape
1
Y se pregunta cómo llamo a esta función para recibir eventos de cambio de tamaño de ventana. Aquí se explica cómo: addEvent (ventana, "redimensionar", función_referencia); :)
oabarca
66
Tenga en cuenta que a partir de IE 11, attachEventya no es compatible. La forma preferida para el futuro es addEventListener.
Lucas
66
Tenga cuidado con el elem == undefined. Es posible (aunque poco probable) que "indefinido" se defina localmente como algo más. stackoverflow.com/questions/8175673/…
Lucas
32

El evento de cambio de tamaño nunca debe usarse directamente, ya que se activa continuamente a medida que cambiamos el tamaño.

Use una función antirrebote para mitigar el exceso de llamadas.

window.addEventListener('resize',debounce(handler, delay, immediate),false);

Aquí hay un rebote común que flota alrededor de la red, aunque busca otros más avanzados como featuerd in lodash.

const debounce = (func, wait, immediate) => {
    var timeout;
    return () => {
        const context = this, args = arguments;
        const later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        const callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Esto se puede usar así ...

window.addEventListener('resize', debounce(() => console.log('hello'),
200, false), false);

Nunca disparará más de una vez cada 200 ms.

Para cambios de orientación móvil, use:

window.addEventListener('orientationchange', () => console.log('hello'), false);

Aquí hay una pequeña biblioteca que reuní para ocuparme de esto cuidadosamente.

frontsideup
fuente
Agradezco la información sobre: ​​debounce (ahora parece un concepto / función invaluable a pesar de que anteriormente me resistí a usar los tiempos de espera de esta manera), lodash (aunque personalmente no estoy convencido) y resolver la ambigüedad sobre si usar addEvent como alternativa addEventListener (solo porque las respuestas anteriores no abordan explícitamente los comentarios al respecto)
wunth
55
Para su información, ya que está utilizando la notación de función de flecha ES6, la función interna debe tener (...arguments) => {...}(o ...argspara menos confusión) ya que la argumentsvariable ya no está disponible en su alcance.
coderatchet
Soy plenamente consciente de que el fragmento no es mi código, es solo un ejemplo.
frontsideup
Gran respuesta, ¡los problemas de rendimiento con el cambio de tamaño deben abordarse! El rebote es una opción, otra es la simple limitación (que podría ser el camino a seguir si necesita que su UI cambie de tamaño en "pasos"). Consulte bencentra.com/code/2015/02/27/optimizing-window-resize.html para ver ejemplos
Robin Métral,
24

Solución para 2018+:

Debe usar ResizeObserver . Es una solución nativa del navegador que tiene un rendimiento mucho mejor que usar el resizeevento. Además, no solo admite el evento en el documentsino también en arbitrario elements.

var ro = new ResizeObserver( entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;
    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

Actualmente, Firefox, Chrome y Safari lo admiten . Para otros navegadores (y más antiguos) debe usar un polyfill .

str
fuente
Sigue siendo la mejor respuesta en 2020 imo
Jesse Reza Khorasanee
16

Creo que @Alex V ya proporcionó la respuesta correcta, pero la respuesta requiere cierta modernización, ya que tiene más de cinco años.

Hay dos problemas principales:

  1. Nunca lo use objectcomo nombre de parámetro. Es una palabra reservada. Dicho esto, la función proporcionada por @Alex V no funcionará strict mode.

  2. La addEventfunción proporcionada por @Alex V no devuelve event objectsi addEventListenerse usa el método. Se debe agregar otro parámetro a la addEventfunción para permitir esto.

NOTA: El nuevo parámetro to addEventse ha hecho opcional para que la migración a esta nueva versión de función no interrumpa ninguna llamada previa a esta función. Todos los usos heredados serán compatibles.

Aquí está la addEventfunción actualizada con estos cambios:

/*
    function: addEvent

    @param: obj         (Object)(Required)

        -   The object which you wish
            to attach your event to.

    @param: type        (String)(Required)

        -   The type of event you
            wish to establish.

    @param: callback    (Function)(Required)

        -   The method you wish
            to be called by your
            event listener.

    @param: eventReturn (Boolean)(Optional)

        -   Whether you want the
            event object returned
            to your callback method.
*/
var addEvent = function(obj, type, callback, eventReturn)
{
    if(obj == null || typeof obj === 'undefined')
        return;

    if(obj.addEventListener)
        obj.addEventListener(type, callback, eventReturn ? true : false);
    else if(obj.attachEvent)
        obj.attachEvent("on" + type, callback);
    else
        obj["on" + type] = callback;
};

Un ejemplo de llamada a la nueva addEventfunción:

var watch = function(evt)
{
    /*
        Older browser versions may return evt.srcElement
        Newer browser versions should return evt.currentTarget
    */
    var dimensions = {
        height: (evt.srcElement || evt.currentTarget).innerHeight,
        width: (evt.srcElement || evt.currentTarget).innerWidth
    };
};

addEvent(window, 'resize', watch, true);
WebWanderer
fuente
Yo diría que attachEvent ya no es relevante en 2017.
Vlad Nicula
@VladNicula Estaría de acuerdo, pero esta respuesta tiene dos años.
WebWanderer
12

Gracias por hacer referencia a mi publicación de blog en http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html .

Si bien puede conectarse al evento de cambio de tamaño de la ventana estándar, encontrará que en IE, el evento se dispara una vez por cada movimiento X y una vez por cada movimiento del eje Y, lo que resulta en una tonelada de eventos que pueden tener un rendimiento impacto en su sitio si la representación es una tarea intensiva.

Mi método implica un breve tiempo de espera que se cancela en los eventos posteriores para que el evento no aparezca en su código hasta que el usuario haya terminado de cambiar el tamaño de la ventana.

Steven
fuente
7
window.onresize = function() {
    // your code
};
saravanakumar
fuente
22
Como dicen muchos de los comentarios anteriores, es mejor no sobrescribir la función onresize; más bien agregue un nuevo evento. Ver la respuesta de Jondlm.
Lucas
6

La siguiente publicación de blog puede serle útil: Arreglar el evento de cambio de tamaño de ventana en IE

Proporciona este código:

Sys.Application.add_load(function(sender, args) {
    $addHandler(window, 'resize', window_resize);
});

var resizeTimeoutId;

function window_resize(e) {
     window.clearTimeout(resizeTimeoutId);
     resizeTimeoutId = window.setTimeout('doResizeCode();', 10);
}
lakshmanaraj
fuente
66
Este es aplicable solo a aplicaciones ASP.NET
Evgeny Gorb
2

Las soluciones mencionadas anteriormente funcionarán si todo lo que desea hacer es cambiar el tamaño de la ventana y solo la ventana. Sin embargo, si desea que el cambio de tamaño se propague a elementos secundarios, deberá propagar el evento usted mismo. Aquí hay un código de ejemplo para hacerlo:

window.addEventListener("resize", function () {
  var recResizeElement = function (root) {
    Array.prototype.forEach.call(root.childNodes, function (el) {

      var resizeEvent = document.createEvent("HTMLEvents");
      resizeEvent.initEvent("resize", false, true);
      var propagate = el.dispatchEvent(resizeEvent);

      if (propagate)
        recResizeElement(el);
    });
  };
  recResizeElement(document.body);
});

Tenga en cuenta que un elemento hijo puede llamar

 event.preventDefault();

en el objeto de evento que se pasa como el primer Arg del evento de cambio de tamaño. Por ejemplo:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});
rysama
fuente
1
<script language="javascript">
    window.onresize = function() {
    document.getElementById('ctl00_ContentPlaceHolder1_Accordion1').style.height = '100%';
} 

</script>
Arenque Rob
fuente
1
var EM = new events_managment();

EM.addEvent(window, 'resize', function(win,doc, event_){
    console.log('resized');
    //EM.removeEvent(win,doc, event_);
});

function events_managment(){
    this.events = {};
    this.addEvent = function(node, event_, func){
        if(node.addEventListener){
            if(event_ in this.events){
                node.addEventListener(event_, function(){
                    func(node, event_);
                    this.events[event_](win_doc, event_);
                }, true);
            }else{
                node.addEventListener(event_, function(){
                    func(node, event_);
                }, true);
            }
            this.events[event_] = func;
        }else if(node.attachEvent){

            var ie_event = 'on' + event_;
            if(ie_event in this.events){
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                    this.events[ie_event]();
                });
            }else{
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                });
            }
            this.events[ie_event] = func;
        }
    }
    this.removeEvent = function(node, event_){
        if(node.removeEventListener){
            node.removeEventListener(event_, this.events[event_], true);
            this.events[event_] = null;
            delete this.events[event_];
        }else if(node.detachEvent){
            node.detachEvent(event_, this.events[event_]);
            this.events[event_] = null;
            delete this.events[event_];
        }
    }
}
LO ASOMBROSO
fuente