JavaScript dispatchEvent не отправляется

У меня проблема с работой dispatchEvent. Я пытаюсь избавиться от зависимости от jQuery и делаю собственные небольшие расширения для собственного API, но не могу заставить мою версию trigger работать с dispatchEvent.

После того, как консоль все записала, я знаю, что eventType передается, объект event создается, а this относится к правильному целевому элементу. Вот код, который у меня есть, буду благодарен за любую помощь.

if (!EventTarget.prototype.trigger) {
    function triggerFunction(
        eventType) {
        const event = new CustomEvent(eventType, {
            bubbles: true,
            cancelable: true
        });

        this.dispatchEvent(event);
    }

    EventTarget.prototype.trigger = triggerFunction;
}

Редактировать

Вот остальной код. На самом деле ничего особенного, потому что я в основном сосредоточился на создании своих расширений.

if (!EventTarget.prototype.on) {
    function onFunction(
        eventType,
        targetElement,
        listener) {
        if (targetElement) {
            this.addEventListener(eventType, function (
                event) {
                const target = event.target;

                if (target
                    && target.nodeName !== targetElement) {
                    return;
                }

                listener.call(target, event);
            }, false);

            return this;
        }

        this.addEventListener(eventType, listener, false);

        return this;
    }

    EventTarget.prototype.on = onFunction;
}

const _pointerTap = "click";

const photosFunction = () => {
    const $buttonPhotosUpload = document.getElementById("button-photos-upload"),
        $fieldPhotosUpload = document.getElementById("field-photos-upload");

    const onButtonPhotosUploadTap = () => $fieldPhotosUpload.trigger(_pointerTap);

    $buttonPhotosUpload.on(_pointerTap, null, onButtonPhotosUploadTap);
};

document.getElementById("photos") && photosFunction();

И HTML:

<div id = "photos">
    <div>
        <button type = "button" id = "button-photos-upload">{UPLOAD}</button>
        <input type = "file" id = "field-photos-upload" accept = "image/*" multiple />
    </div>
</div>

В основном, когда кнопка нажата, я хочу вызвать событие щелчка файла input:, чтобы я мог визуально скрыть его с помощью CSS. В моей версии jQuery это работает нормально.

У меня отлично работает. jsfiddle.net/gftey7qs Если вы все еще испытываете это, можете ли вы отредактировать свой вопрос, чтобы показать, какой другой код вы используете (например, прикрепленный прослушиватель событий, который не запускается должным образом), чтобы у нас был минимальный воспроизводимый пример для отладки?

CertainPerformance 11.01.2019 02:11

Я добавил остальную часть кода, ничего особенного, так как я только начинал.

Gup3rSuR4c 11.01.2019 04:02

Я добавил функцию on, _pointerTap там был, наверное не выбирал при копировании / вставке. Я обновил скрипку, и она ведет себя так же, как и мой проект, то есть не запускает щелчок. jsfiddle.net/n2jbskh8/1

Gup3rSuR4c 11.01.2019 04:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
1 842
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вот гораздо более минималистичный MCVE:

function triggerFunction(eventType) {
  const event = new CustomEvent(eventType, {
    bubbles: true,
    cancelable: true
  });
  this.dispatchEvent(event);
}
if (!EventTarget.prototype.trigger) {
  EventTarget.prototype.trigger = triggerFunction;
}

const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
  // input.click(); // Works
  // input.trigger('click'); // Doesn't work
});
<div>
  <button type = "button">{UPLOAD}</button>
  <input type = "file">
</div>

Проблема в том, что отправленное событие не запускает функцию (встроенный в браузер), которая открывает диалоговое окно ввода. Отправленное событие делает запускает другие обычные слушатели.

Я сомневаюсь, что есть какой-либо способ сделать это без вызова встроенной функции click, которая вызывает собственный код браузера, который позволяет открывать диалоговое окно. Одна из возможностей - проверить, является ли eventTypeclick, а EventTarget - HTMLElement. Кажется, что можно обойти проблему, но я не думаю, что есть другой способ, когда цель требует вызова собственный код браузера для диалога.

function triggerFunction(eventType) {
  if (this instanceof HTMLInputElement && eventType === 'click') {
    return HTMLElement.prototype.click.call(this);
  }
  const event = new CustomEvent(eventType, {
    bubbles: true,
    cancelable: true
  });
  this.dispatchEvent(event);
}
if (!EventTarget.prototype.trigger) {
  EventTarget.prototype.trigger = triggerFunction;
}

const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
  input.trigger('click'); // Works
});
<div>
  <button type = "button">{UPLOAD}</button>
  <input type = "file">
</div>

Аналогичный шаблон потребуется при вызове любого метода, который требует запуска собственного кода (например, console.info или XMLHttpRequest, если fetch недоступен, или setTimeout - некоторые вещи просто невозможно эмулировать с помощью вашего собственного Javascript и требуют вызова некоторого собственного кода. браузера).

Также обратите внимание, что похоже, что вы просто пытаетесь добавить собственные методы в HTML-элементы, и в этом случае было бы неплохо назначить trigger для HTMLElement.prototype, а не EventTarget.prototype:

function triggerFunction(eventType) {
  if (this instanceof HTMLInputElement && eventType === 'click') {
    return HTMLElement.prototype.click.call(this);
  }
  const event = new CustomEvent(eventType, {
    bubbles: true,
    cancelable: true
  });
  this.dispatchEvent(event);
}
if (!HTMLElement.prototype.trigger) {
  HTMLElement.prototype.trigger = triggerFunction;
}

const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
  input.trigger('click'); // Works
});
<div>
  <button type = "button">{UPLOAD}</button>
  <input type = "file">
</div>

На самом деле dispatchEvent (MouseEvent) сработал бы.

Kaiido 11.01.2019 06:42
Ответ принят как подходящий

Дело в том, что браузеры не только смотрят на свойство type вашего события, они также требуют, чтобы оно унаследовало от правильного подкласса Event.

В этом случае единственный подкласс Event, который им нужен, - это MouseEvent, поэтому вместо dispatchEvent(new CustomEvent('click')); вам придется использовать dispatchEvent(new MouseEvent('click')).

(MCVE заимствовано из ответа @CertainPerformance).

function triggerMouseFunction(eventType) {
  // here event must be MouseEvent for it to work on <input>
  const event = new MouseEvent(eventType, {
    bubbles: true,
    cancelable: true
  });
  this.dispatchEvent(event);
}
if (!EventTarget.prototype.triggerMouse) {
  EventTarget.prototype.triggerMouse = triggerMouseFunction;
}

const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
  input.triggerMouse('click'); // Works
});
<div>
  <button type = "button">{UPLOAD}</button>
  <input type = "file">
</div>

Но если все, что вам нужно, это действительно вызвать событие щелчка, то непременно используйте HTMLElement.click().

Нет необходимости ни в какой библиотеке, ни в изменении прототипа EventTarget, что является очень плохой идеей.

const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
  input.click(); // Works
});
<div>
  <button type = "button">{UPLOAD}</button>
  <input type = "file">
</div>

Спасибо, вот и все! Я добавил функцию getEvent, чтобы включить eventType и вернуть правильный объект. Мне нужно, чтобы он обрабатывал не только событие щелчка, потому что в конечном итоге я хочу удалить свою зависимость от jQuery для этого проекта. Еще раз спасибо!

Gup3rSuR4c 11.01.2019 16:15

Благодаря @Kaiido, теперь он снова работает. Я добавил функцию getEvent, чтобы включить eventType и вернуть правильный объект Event. Обновленный код выглядит так:

function getEvent(
    eventType): Event {
    switch (eventType) {
        case "keydown":
        case "keypress":
        case "keyup":
            return new KeyboardEvent(eventType);
        case "click":
        case "dblclick":
        case "mouseup":
        case "mousedown":
            return new MouseEvent(eventType);
        default:
            return new CustomEvent(eventType);
    }
}

function triggerFunction(
    eventType) {
    const event = getEvent(eventType);

    event.bubbles = true;
    event.cancelable = true;

    this.dispatchEvent(event);
}

if (!EventTarget.prototype.trigger) {
    EventTarget.prototype.trigger = triggerFunction;
}

Другие вопросы по теме