Le constructeur d'événements Internet Explorer 9, 10 et 11 ne fonctionne pas

129

Je crée un événement, alors utilisez le constructeur d'événement DOM:

new Event('change');

Cela fonctionne bien dans les navigateurs modernes, mais dans Internet Explorer 9, 10 et 11, cela échoue avec:

Object doesn't support this action

Comment puis-je réparer Internet Explorer (idéalement via un polyfill)? Si je ne peux pas, y a-t-il une solution de contournement que je peux utiliser?

Mikemaccana
la source
56
"Comment puis-je réparer Internet Explorer?" xD
contactmatt

Réponses:

176

Il existe un polyfill IE pour le constructeur CustomEvent chez MDN . L'ajout de CustomEvent à IE et son utilisation fonctionnent à la place.

(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
la source
14
Vous monsieur m'a sauvé la vie. Serait-il prudent de faire une substitution complète? Je veux dire, faire window.Event= CustomEventsur la dernière ligne.
tfrascaroli le
7
Dans IE11, il semble être sûr de définir window.Event = CustomEvent, oui.
Corey Alix
10
Pour toute personne intéressée, il semble possible de détecter que vous êtes dans IE (dans ce cas) en vérifiant typeof (Event) qui est «fonction» pour tous sauf IE où c'est «objet». Vous pouvez ensuite polyfill en toute sécurité le constructeur Event en utilisant l'approche ci-dessus.
Euan Smith
J'étudie juste une solution de contournement similaire StorageEventet typeof(StorageEvent)ne fonctionne pas dans MS Edge. Cela fonctionne: try { new StorageEvent(); } catch (e) { /* polyfill */ }.
kamituel
1
Il peut ne pas être sûr de remplacer window.CustomEvent, si vous utilisez des bibliothèques tierces qui utilisent le constructeur CustomEvent défini par IE.
Sen Jacob
55

Je pense que la meilleure solution pour résoudre votre problème et gérer la création d'événements multi-navigateurs est:

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
la source
3
Ça marche! Je pense juste que ça devrait return eventpour que je puisse le transmettre dispatchEvent().
Noumenon
initEventest vieux et obsolète , vous devez au moins utiliser la méthode moderne et comme solution de secours, utilisez la méthode obsolète.
vsync
2
@vsync Cela peut être obsolète, mais les documents que vous avez liés disent "Utilisez plutôt des constructeurs d'événements spécifiques, comme Event ()", ce qui est exactement ce que cela essaie de polyfill, donc il n'y a pas vraiment de choix.
rédigé
1
CustomEventpermet de transmettre des données personnalisées via l' detailoption, et Eventne le fait pas. Ai-je tort?
pttsky
1
CustomEvent n'est pas pris en charge pour IE9, 10 ou 11 selon ma propre expérience. La seule bonne réponse semble être l'acceptation.
UndyingJellyfish
5

Ce package fait la magie:

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

Incluez le colis et envoyez l'événement comme suit:

window.dispatchEvent(new window.CustomEvent('some-event'))
fsavina
la source
95 dépendances?
Damien Roche
4
@DamienRoche Est-ce que vous avez mal lu "Dependents" comme "Dependencies"? Parce que le paquet a en fait 0 dépendances et (au moment de l'écriture) 102 dépendants (c'est-à-dire des paquets qui en dépendent). Ces 102 paquets dépendants étaient probablement 95 en juillet.
grippe
2
J'ai bien fait! : P
Damien Roche
3

Si vous essayez simplement de distribuer un événement simple comme l'événement de bascule HTML, cela fonctionne dans Internet Explorer 11 ainsi que dans les autres navigateurs:

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
la source
5
Je ne vois pas pourquoi vous mélangez es6 let(et ne l'utilisez pas var) avec un code censé fonctionner sur l'ancien IE .. cela pourrait dérouter les débutants qui vont copier-coller ceci
vsync
1
@vsync hausser les épaules , je l'ai fait mentionner le numéro de version. Mon site Web personnel ne ciblait IE11 que l'année dernière, il ne m'est donc jamais venu à l'esprit de vérifier le support dans les anciennes versions. (À partir d'aujourd'hui, je sers du HTML brut IE11 sans feuilles de style ni scripts. Les gens doivent passer à autre chose.) Dans tous les cas, la seule version d'Internet Explorer toujours prise en charge par Microsoft à partir d'avril 2017 est la version 11, donc c'est un peu un point discutable. Je n'encourage personne à utiliser un navigateur non compatible en le ciblant. Le Web peut être un endroit dangereux.
Patrick Dark
3
il ne s'agit pas du tout de cela, ni d'essayer de changer le monde ou quoi que ce soit. Par exemple, le titre de la question demande spécifiquement pour IE 9et au-dessus, et peut-être qu'une personne cherchant une réponse qui trouve ce fil, développe une application pour le système bancaire hérité ou un autre système pour les clients commerciaux qui n'ont aucun contrôle sur leurs ordinateurs et sont obligé de travailler avec l'ancien IE. cela n'a rien à voir avec le support Microsoft ..
vsync
3

Il existe un service polyfill qui peut corriger cela et d'autres pour vous

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

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

le custom-eventpackage npm a parfaitement fonctionné pour moi

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
la source
C'est une bonne réponse, mais il existe déjà un autre package NPM mentionné comme réponse.
mikemaccana
2
Quel est le problème à offrir aux utilisateurs une variété d'options?
Liran H
Un package plus générique est npmjs.com/package/events-polyfill
Markus Jarderot
1

J'utilise personnellement une fonction wrapper pour gérer les événements créés manuellement. Le code suivant ajoutera une méthode statique sur toutes les Eventinterfaces (toutes les variables globales se terminant par Eventsont une interface d'événement) et vous permettra d'appeler des fonctions comme element.dispatchEvent(MouseEvent.create('click'));sur 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)));

EDIT: La fonction de recherche de toutes les Eventinterfaces peut également être remplacée par un tableau pour modifier uniquement les interfaces d'événement dont vous avez besoin ( ['Event', 'MouseEvent', 'KeyboardEvent', 'UIEvent' /*, etc... */]).

Kevin Drost
la source