El constructor de eventos de Internet Explorer 9, 10 y 11 no funciona

129

Estoy creando un evento, así que use el constructor de eventos DOM:

new Event('change');

Esto funciona bien en los navegadores modernos, sin embargo, en Internet Explorer 9, 10 y 11, falla con:

Object doesn't support this action

¿Cómo puedo arreglar Internet Explorer (idealmente a través de un polyfill)? Si no puedo, ¿hay alguna solución que pueda usar?

mikemaccana
fuente
55
"¿Cómo puedo arreglar Internet Explorer?" xD
contactmatt

Respuestas:

176

Hay un polyfill de IE para el constructor CustomEvent en MDN . Agregar CustomEvent a IE y usarlo en su lugar funciona.

(function () {
  if ( typeof window.CustomEvent === "function" ) return false; //If not IE

  function CustomEvent ( event, params ) {
    params = params || { bubbles: false, cancelable: false, detail: undefined };
    var evt = document.createEvent( 'CustomEvent' );
    evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
    return evt;
   }

  CustomEvent.prototype = window.Event.prototype;

  window.CustomEvent = CustomEvent;
})();
mikemaccana
fuente
14
Usted señor me salvó la vida. ¿Sería seguro hacer una sustitución completa? Quiero decir, haciendo window.Event= CustomEventen la última línea.
tfrascaroli
77
En IE11 parece seguro configurar window.Event = CustomEvent, sí.
Corey Alix
10
Para cualquier persona interesada, parece posible detectar que está en IE (para este caso) marcando typeof (Evento) que es 'función' para todos excepto IE donde es 'objeto'. Luego puede rellenar con seguridad el constructor de eventos utilizando el enfoque anterior.
Euan Smith el
Solo estoy investigando una solución similar para MS Edge StorageEventy typeof(StorageEvent)no funciona. Esto funciona: try { new StorageEvent(); } catch (e) { /* polyfill */ }.
kamituel
1
Es posible que no sea seguro sustituir window.CustomEvent, si está utilizando bibliotecas de terceros que utilizan el constructor CustomEvent definido por IE.
Sen Jacob
55

Creo que la mejor solución para resolver su problema y tratar con la creación de eventos entre navegadores es:

function createNewEvent(eventName) {
    var event;
    if (typeof(Event) === 'function') {
        event = new Event(eventName);
    } else {
        event = document.createEvent('Event');
        event.initEvent(eventName, true, true);
    }
    return event;
}
michalduda
fuente
3
¡Funciona! Solo creo que debería return eventpara poder pasárselo dispatchEvent().
Noumenon
initEventes antiguo y está en desuso , necesita al menos usar la forma moderna y, como alternativa, usar la forma en desuso.
vsync
2
@vsync Puede estar en desuso, pero los documentos que vinculó para decir "En su lugar, use constructores de eventos específicos, como Event ()", que es exactamente lo que está tratando de rellenar, por lo que no hay otra opción.
reducido el
1
CustomEventpermite pasar datos personalizados a través de la detailopción, y Eventno lo hace. ¿Me equivoco?
pttsky
1
CustomEvent no es compatible con IE9, 10 u 11, según mi propia experiencia. La única buena respuesta parece ser la aceptada.
UndyingJellyfish
5

Este paquete hace la magia:

https://www.npmjs.com/package/custom-event-polyfill

Incluya el paquete y envíe el evento de la siguiente manera:

window.dispatchEvent(new window.CustomEvent('some-event'))
fsavina
fuente
95 dependencias?
Damien Roche
44
@DamienRoche ¿Podría ser que leyó mal a "Dependientes" como "Dependencias"? Porque el paquete en realidad tiene 0 dependencias y (al momento de escribir) 102 dependientes (es decir, paquetes que dependen de él). Esos 102 paquetes dependientes probablemente fueron 95 en julio.
gripe
2
¡Lo hice muy bien! : P
Damien Roche
3

Si solo está tratando de enviar un evento simple como el evento de alternancia HTML, esto funciona en Internet Explorer 11 y en los otros navegadores:

let toggle_event = null;
try {
    toggle_event = new Event("toggle");
}
catch (error) {
    toggle_event = document.createEvent("Event");
    let doesnt_bubble = false;
    let isnt_cancelable = false;
    toggle_event.initEvent("toggle", doesnt_bubble, isnt_cancelable);
}
// disclosure_control is a details element.
disclosure_control.dispatchEvent(toggle_event);
Patrick Dark
fuente
55
no puedo ver por qué estás mezclando es6 let(y no usas var) con un código que se supone que se ejecuta en un IE antiguo ... podría confundir a los principiantes que copiarán y
pegarán
1
@vsync encogerse lo hice mencionar el número de versión. Mi sitio web personal solo estaba dirigido a IE11 el año pasado, por lo que nunca se me ocurrió verificar el soporte en versiones anteriores. (A partir de hoy, sirvo IE11 HTML simple sin hojas de estilo o scripts. La gente necesita seguir adelante.) En cualquier caso, la única versión de Internet Explorer que todavía es compatible con Microsoft a partir de abril de 2017 es la versión 11, por lo que es un poco punto discutible. No recomendaría a nadie que use un navegador no compatible si lo selecciona como objetivo. La web puede ser un lugar peligroso.
Patrick Dark el
3
no se trata de eso en absoluto, y no se trata de tratar de cambiar el mundo ni nada. Por ejemplo, el título de la pregunta específicamente pide IE 9y más arriba, y tal vez una persona que busca una respuesta que encuentra este hilo, está desarrollando una aplicación para el sistema bancario heredado o algún otro sistema para clientes comerciales que no tienen control sobre sus computadoras y están obligado a trabajar con viejos IE. esto no tiene nada que ver con el soporte técnico de Microsoft ..
VSYNC
3

Hay un servicio de polyfill que puede parchear este y otros para usted

https://polyfill.io/v3/url-builder/

 <script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js"></script>
frumbert
fuente
2

el custom-eventpaquete npm funcionó muy bien para mí

https://www.npmjs.com/package/custom-event

var CustomEvent = require('custom-event');

// add an appropriate event listener
target.addEventListener('cat', function(e) { process(e.detail) });

// create and dispatch the event
var event = new CustomEvent('cat', {
  detail: {
    hazcheeseburger: true
  }
});
target.dispatchEvent(event);
Liran H
fuente
Esta es una buena respuesta, pero ya hay otro paquete NPM mencionado como respuesta.
mikemaccana
2
¿Qué tiene de malo dar a los usuarios una variedad de opciones?
Liran H
Un paquete más genérico es npmjs.com/package/events-polyfill
Markus Jarderot
1

Personalmente uso una función de contenedor para manejar eventos creados manualmente. El siguiente código agregará un método estático en todas las Eventinterfaces (todas las variables globales que terminan en Eventuna interfaz de Evento) y le permitirá llamar a funciones como element.dispatchEvent(MouseEvent.create('click'));en IE9 +.

(function eventCreatorWrapper(eventClassNames){
    eventClassNames.forEach(function(eventClassName){
        window[eventClassName].createEvent = function(type,bubbles,cancelable){
            var evt
            try{
                evt = new window[eventClassName](type,{
                    bubbles: bubbles,
                    cancelable: cancelable
                });
            } catch (e){
                evt = document.createEvent(eventClassName);
                evt.initEvent(type,bubbles,cancelable);
            } finally {
                return evt;
            }
        }
    });
}(function(root){
    return Object.getOwnPropertyNames(root).filter(function(propertyName){
        return /Event$/.test(propertyName)
    });
}(window)));

EDITAR: La función para buscar todas las Eventinterfaces también se puede reemplazar por una matriz para alterar solo las interfaces de eventos que necesita ( ['Event', 'MouseEvent', 'KeyboardEvent', 'UIEvent' /*, etc... */]).

Kevin Drost
fuente