O construtor de eventos do Internet Explorer 9, 10 e 11 não funciona

129

Como estou criando um evento, use o construtor DOM Event:

new Event('change');

Isso funciona bem em navegadores modernos; no entanto, no Internet Explorer 9, 10 e 11, falha com:

Object doesn't support this action

Como posso corrigir o Internet Explorer (de preferência através de um polyfill)? Se não puder, há uma solução alternativa que posso usar?

mikemaccana
fonte
55
"como posso corrigir o Internet Explorer?" xD
contactmatt

Respostas:

176

Há um polyfill do IE para o construtor CustomEvent na MDN . Adicionar CustomEvent ao IE e usá-lo 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
fonte
14
Você senhor salvou minha vida. Seria seguro fazer uma substituição completa? Quero dizer, fazendo window.Event= CustomEventna última linha.
Tfrascaroli 2/06
7
No IE11, parece seguro definir window.Event = CustomEvent, sim.
Corey Alix
10
Para qualquer pessoa interessada, parece possível detectar que você está no IE (neste caso) verificando typeof (Event), que é 'função' para todos, exceto o IE, onde é 'objeto'. Em seguida, é possível preencher com segurança o construtor Event usando a abordagem acima.
precisa
Estou apenas investigando uma solução semelhante StorageEvente typeof(StorageEvent)não funciona no MS Edge. Isso funciona: try { new StorageEvent(); } catch (e) { /* polyfill */ }.
Kamituel
1
Pode não ser seguro substituir window.CustomEvent, se você estiver usando bibliotecas de terceiros que usam o construtor CustomEvent definido pelo IE.
Sen Jacob
55

Acho que a melhor solução para resolver seu problema e lidar com a criação de eventos entre navegadores é:

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
fonte
3
Funciona! Eu só acho que deveria, return eventpara que eu possa passar dispatchEvent().
Noumenon
initEventé antigo e descontinuado , você precisa pelo menos usar a maneira moderna e, como alternativa, usar a maneira descontinuada.
vsync 24/10
2
@ vsync Pode ser preterido, mas os documentos que você vinculou dizem "Em vez disso, use construtores de eventos específicos, como Event ()", que é exatamente o que isso está tentando polifill, por isso não há escolha.
reduckted
1
CustomEventpermite passar dados personalizados através da detailopção, e Eventnão. Estou errado?
pttsky
1
O CustomEvent não é suportado no IE9, 10 ou 11, de acordo com minha própria experiência. A única boa resposta parece ser a aceita.
UndyingJellyfish
5

Este pacote faz a mágica:

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

Inclua o pacote e despache o evento da seguinte maneira:

window.dispatchEvent(new window.CustomEvent('some-event'))
fsavina
fonte
95 dependências?
Damien Roche
4
@DamienRoche Será que você leu "Dependentes" como "Dependências"? Porque o pacote realmente possui 0 dependências e (no momento da redação) 102 dependentes (ou seja, pacotes que dependem dele). Que 102 pacotes dependentes provavelmente tinham 95 em julho.
gripe
2
Eu realmente fiz! : P
Damien Roche
3

Se você está apenas tentando enviar um evento simples, como o evento de alternância de HTML, isso funciona no Internet Explorer 11 e nos outros 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
fonte
5
não posso ver porque você está misturando es6 let(e não usar var) com um código deveria ser executado no velho IE .. isso pode confundir os iniciantes que vai copiar e colar este
vsync
1
@vsync encolher I fez mencionar o número da versão. Meu site pessoal tinha como alvo apenas o IE11 no ano passado, portanto nunca me ocorreu verificar o suporte em versões mais antigas. (Atualmente, eu sirvo HTML simples do IE11 sem folhas de estilo ou scripts. As pessoas precisam seguir em frente.) De qualquer forma, a única versão do Internet Explorer ainda suportada pela Microsoft em abril de 2017 é a versão 11, portanto, é um pouco ponto discutível. Eu não incentivaria ninguém a usar um navegador não suportado, segmentando-o. A Web pode ser um lugar perigoso.
Patrick Dark
3
não é sobre isso, nem sobre tentar mudar o mundo ou algo assim. Por exemplo, o título da pergunta solicita especificamente IE 9e acima, e talvez uma pessoa que procura uma resposta que encontre esse segmento, esteja desenvolvendo um aplicativo para o sistema bancário herdado ou algum outro sistema para clientes corporativos que não têm controle sobre seus computadores e são obrigado a trabalhar com o antigo IE. isso não tem nada a ver com o suporte da Microsoft ..
vsync
3

Existe um serviço de polyfill que pode corrigir isso e outros para você

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

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

o custom-eventpacote npm funcionou lindamente para mim

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
fonte
Essa é uma boa resposta, mas já existe outro pacote do NPM mencionado como resposta.
Mikemaccana
2
O que há de errado em oferecer aos usuários uma variedade de opções?
Liran H
Um pacote mais genérico é npmjs.com/package/events-polyfill
Markus Jarderot
1

Pessoalmente, uso uma função de wrapper para manipular eventos criados manualmente. O código a seguir adicionará um método estático em todas as Eventinterfaces (todas as variáveis ​​globais terminadas em Eventsão uma interface de eventos) e permitirá que você chame funções como element.dispatchEvent(MouseEvent.create('click'));no 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: A função para encontrar todas as Eventinterfaces também pode ser substituída por uma matriz para alterar apenas as interfaces de evento necessárias ( ['Event', 'MouseEvent', 'KeyboardEvent', 'UIEvent' /*, etc... */]).

Kevin Drost
fonte