От создателя: события находятся всюду в веб-приложениях. От события DOMContentLoaded, которое запускается немедля, когда браузер завершает загрузку и анализирует HTML, до события unload, которое запускается конкретно перед тем, как юзер покидает ваш веб-сайт. Опыт использования веб-приложения, на самом деле, представляет собой просто серию событий. Для разрабов эти события помогают найти, что лишь что вышло в приложении, какое состояние юзера было в конкретное время и почти все другое.
Время от времени доступные события JavaScript неадекватно либо некорректно обрисовывают состояние приложения. К примеру, в случае сбоя входа юзера в систему. И вы желаете, чтоб родительский компонент либо элемент знал о нарушении. Не существует события сбоя входа либо чего-либо подобного, доступного для отправки.
К счастью, есть метод создавать пользовательские события JavaScript для вашего приложения, о чем мы поведаем в этом руководстве. Мы тщательно разглядим последующее:
Как сделать пользовательское событие в JavaScript
Внедрение конструктора событий
Внедрение конструктора CustomEvent
Отправка пользовательских событий в JavaScript
Как работают пользовательские события JavaScript?
Перетаскивание JavaScript
Как применять деструктуризацию объекта в JavaScript
Чтоб следовать этому управлению, вы обязаны иметь базисные познания о:
HTML и CSS
JavaScript и ES6
DOM и манипуляции с DOM
Давайте начнем!
Как сделать пользовательское событие в JavaScript
Пользовательские события можно создавать 2-мя методами:
Внедрение конструктора Event
Внедрение конструктора CustomEvent
Пользовательские события также могут быть сделаны при помощи document.createEvent, но большая часть способов предоставляемых объектом, возвращаемым из функции, устарели.
Внедрение конструктора Event
Пользовательское событие быть может сотворено при помощи конструктора Event, к примеру:
JavaScript const myEvent = new Event(‘myevent’, { bubbles: true, cancelable: true, composed: false
})
12345 | const myEvent = new Event(‘myevent’, { bubbles: true, cancelable: true, composed: false}) |
В приведенном выше фрагменте мы сделали событие myevent, передав имя события конструктору Event. Имена событий нечувствительны к регистру, потому myevent такое же, как myEvent и MyEvent и т.д. Конструктор события также воспринимает объект, который описывает некие принципиальные характеристики, касающиеся события.
bubbles
Свойство bubbles описывает, обязано ли событие распространяться ввысь к родительскому элементу. Установка значения true значит, что если событие отчаливает в дочернем элементе, родительский элемент может прослушивать событие и делать действие на его базе. Это поведение большинства нативных событий DOM, но для пользовательских событий по дефлоту установлено false.
Если вы желаете, чтоб событие отчаливало лишь определенному элементу, вы сможете приостановить распространение события при помощи event.stopPropagation(). Это обязано быть в оборотном вызове, который прослушивает событие. Подробнее о этом позднее.
cancelable
Как надо из наименования, cancelable показывает, обязано ли событие быть отменяемым. Нативные события DOM можно отменять по дефлоту, потому вы сможете вызывать event.preventDefault(), что предупредит действие события по дефлоту. Если для пользовательского события cancelable установлено значение false, при вызове event.preventDefault() не производится никаких действий.
composed
Свойство composed описывает, обязано ли это событие всплывать из теневого DOM (сделанные при использовании интернет — компонент) к реальному DOM. Если для bubbles установлено значение false, это не имеет значения, поэтому что вы очевидно указываете событию не всплывать ввысь. Но, если вы желаете выслать пользовательское событие в веб-компонент и прослушивать его на родительском элементе в настоящей модели DOM, то для скомпонованного характеристики нужно установить значение true.
Недочетом использования этого способа будет то, что вы не сможете отправлять данные слушателю. Но в большинстве приложений мы желали бы иметь возможность отправлять данные от того места, где событие отчаливает слушателю. Для этого мы можем применять контроллер CustomEvent.
Новое во Vue: Что ожидать во Vue 3
Вы также не сможете отправлять данные с внедрением собственных событий DOM. Данные могут быть получены лишь от цели события.
Внедрение конструктора CustomEvent
Пользовательское событие можно сделать при помощи конструктора CustomEvent:
JavaScript const myEvent = new CustomEvent(«myevent», { detail: {}, bubbles: true, cancelable: true, composed: false,
});
123456 | const myEvent = new CustomEvent(«myevent», { detail: {}, bubbles: true, cancelable: true, composed: false,}); |
Как показано выше, создание пользовательского события при помощи конструктора CustomEvent аналогично созданию события при помощи конструктора Event. Единственное отличие состоит в том, что объект передается в конструктор как 2-ой параметр.
При разработке событий при помощи конструктора Event мы были ограничены тем, что мы не можем передавать данные через событие слушателю. Тут любые данные, которые нужно передать слушателю, можно передать в свойстве detail, которое создается при инициализации события.
Отправка пользовательских событий в JavaScript
Опосля сотворения событий у вас обязана быть возможность отправлять их. События могут быть высланы хоть какому расширяющемуся объекту EventTarget, и они включают в себя все элементы HTML, документ, окно и т.д. Вы сможете отправлять пользовательские события последующим образом:
JavaScript const myEvent = new CustomEvent(«myevent», { detail: {}, bubbles: true, cancelable: true, composed: false, });
document.querySelector(«#someElement»).dispatchEvent(myEvent);
1234567 | const myEvent = new CustomEvent(«myevent», { detail: {}, bubbles: true, cancelable: true, composed: false,});document.querySelector(«#someElement»).dispatchEvent(myEvent); |
Чтоб прослушивать настраиваемое событие, добавьте прослушиватель событий к элементу, который вы желаете прослушивать, так же, как и с нативными событиями DOM.
JavaScript document.querySelector(«#someElement»).addEventListener(«myevent», (event) => { console.log(«I’m listening on a custom event»);
});
123 | document.querySelector(«#someElement»).addEventListener(«myevent», (event) => { console.log(«I’m listening on a custom event»);}); |
Как работают пользовательские события JavaScript?
Чтоб показать, как применять пользовательские события в приложении JavaScript, мы сделаем обычное приложение, которое дозволяет юзерам добавлять профиль и автоматом получать карточку профиля.
Создание пользовательского интерфейса
Сделайте папку, назовите ее как желаете и сделайте в папке файл index.html. Добавьте последующее в index.html:
Custom Events Application
Profile Card
Enter Profile Details
Drag an Image into this section or select an image Enter Name Enter Occupation
No Name Entered No Occupation Entered
1234567891011121314151617181920212223242526272829303132333435363738394041 | Custom Events Application
Profile Card
Enter Profile DetailsDrag an Image into this section or select an image Enter Name Enter Occupation No Name Entered No Occupation Entered |
Тут мы добавляем разметку для странички. Страничка состоит из 2-ух разделов. 1-ый раздел — это форма, которая дозволяет юзеру созодать последующее:
Загрузить изображение при помощи перетаскивания либо вручную изберите файл изображения
Ввести имя
Ввести профессию
Данные, приобретенные из формы, будут отображаться во 2-м разделе — карточке профиля. 2-ой раздел просто содержит текст и изображения-заполнители. Данные, приобретенные из формы, перезапишут данные заполнителя содержимого. Сделайте файл style.css и заполните его последующим образом:
CSS * { box-sizing: border-box; } h1 { text-align: center; } main { display: flex; margin-top: 50px; justify-content: space-evenly; } .form { flex-basis: 500px; border: solid 1px #cccccc; padding: 10px 50px; box-shadow: 0 0 3px #cccccc; border-radius: 5px; } .form section { border: dashed 2px #aaaaaa; border-radius: 5px; box-shadow: 0 0 3px #aaaaaa; transition: all 0.2s; margin-bottom: 30px; padding: 50px; font-size: 1.1rem; } .form section:hover { box-shadow: 0 0 8px #aaaaaa; border-color: #888888; } .form section label { text-decoration: underline #000000; cursor: pointer; } .form-group { margin-bottom: 25px; } .form-group label { display: block; margin-bottom: 10px; } .form-group input { width: 100%; padding: 10px; border-radius: 5px; border: solid 1px #cccccc; box-shadow: 0 0 2px #cccccc; } #file-input { display: none; } .profile-card { flex-basis: 300px; border: solid 2px #cccccc; border-radius: 5px; box-shadow: 0 0 5px #cccccc; padding: 40px 35px; align-self: center; display: flex; flex-direction: column; justify-content: center; align-items: center; } .img-container { margin-bottom: 50px; } .img-container img { border-radius: 50%; width: 200px; height: 200px; } .profile-card .name { margin-bottom: 10px; font-size: 1.5rem; } .profile-card .occupation { font-size: 1.2rem;
}
Angular: Как создать полноэкранный календарь, такой как в Outlook
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 | * { box-sizing: border-box;}h1 { text-align: center;}main { display: flex; margin-top: 50px; justify-content: space-evenly;}.form { flex-basis: 500px; border: solid 1px #cccccc; padding: 10px 50px; box-shadow: 0 0 3px #cccccc; border-radius: 5px;}.form section { border: dashed 2px #aaaaaa; border-radius: 5px; box-shadow: 0 0 3px #aaaaaa; transition: all 0.2s; margin-bottom: 30px; padding: 50px; font-size: 1.1rem;}.form section:hover { box-shadow: 0 0 8px #aaaaaa; border-color: #888888;}.form section label { text-decoration: underline #000000; cursor: pointer;}.form-group { margin-bottom: 25px;}.form-group label { display: block; margin-bottom: 10px;}.form-group input { width: 100%; padding: 10px; border-radius: 5px; border: solid 1px #cccccc; box-shadow: 0 0 2px #cccccc;}#file-input { display: none;}.profile-card { flex-basis: 300px; border: solid 2px #cccccc; border-radius: 5px; box-shadow: 0 0 5px #cccccc; padding: 40px 35px; align-self: center; display: flex; flex-direction: column; justify-content: center; align-items: center;}.img-container { margin-bottom: 50px;}.img-container img { border-radius: 50%; width: 200px; height: 200px;}.profile-card .name { margin-bottom: 10px; font-size: 1.5rem;}.profile-card .occupation { font-size: 1.2rem;} |
В конце концов, сделайте файл, чтоб вы могли добавить функциональность в приложение index.js.
Перетаскивание в JavaScript
1-ая функция, которую мы добавим в приложение, — это возможность загружать изображения. Для этого мы будем поддерживать перетаскивание, также загрузку вручную. Добавьте в файл JavaScript:
JavaScript const section = document.querySelector(«.form section»);
section.addEventListener(«dragover», handleDragOver); section.addEventListener(«dragenter», handleDragEnter);
section.addEventListener(«drop», handleDrop);
/** * @param {DragEvent} event */ function handleDragOver(event) { // Only allow files to be dropped here. if (!event.dataTransfer.types.includes(«Files»)) { return; } event.preventDefault(); // Specify Drop Effect. event.dataTransfer.dropEffect = «copy»;
}
/** * @param {DragEvent} event */ function handleDragEnter(event) { // Only allow files to be dropped here. if (!event.dataTransfer.types.includes(«Files»)) { return; } event.preventDefault();
}
/** * @param {DragEvent} event */ function handleDrop(event) { event.preventDefault(); // Get the first item here since we only want one image const file = event.dataTransfer.files[0]; // Check that file is an image. if (!file.type.startsWith(«image/»)) { alert(«Only image files are allowed.»); return; } handleFileUpload(file);
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344 | const section = document.querySelector(«.form section»); section.addEventListener(«dragover», handleDragOver);section.addEventListener(«dragenter», handleDragEnter);section.addEventListener(«drop», handleDrop); /** * @param {DragEvent} event */function handleDragOver(event) { // Only allow files to be dropped here. if (!event.dataTransfer.types.includes(«Files»)) { return; } event.preventDefault(); // Specify Drop Effect. event.dataTransfer.dropEffect = «copy»;} /** * @param {DragEvent} event */function handleDragEnter(event) { // Only allow files to be dropped here. if (!event.dataTransfer.types.includes(«Files»)) { return; } event.preventDefault();} /** * @param {DragEvent} event */function handleDrop(event) { event.preventDefault(); // Get the first item here since we only want one image const file = event.dataTransfer.files[0]; // Check that file is an image. if (!file.type.startsWith(«image/»)) { alert(«Only image files are allowed.»); return; } handleFileUpload(file);} |
Тут мы избираем раздел из DOM. Это дозволяет прослушивать надлежащие события, которые нужны для обеспечения операции перетаскивания — а конкретно dragover, dragenter и drop.
В функции handleDragOver мы гарантируем, что перетаскиваемый элемент является файлом, и устанавливаем эффект перетаскивания на copy. handleDragEnter также делает аналогичную функцию, гарантируя, что мы обрабатываем лишь перетаскивание файлов.
Фактическая функциональность реализуется, когда файл удаляется, и мы обрабатываем это при помощи handleDrop. Во-1-х, мы предотвратим действие браузера по дефлоту, которое заключается в открытии файла перед его доставкой.
Мы подтверждаем, что файл является изображением. Если это не так, мы отправляем сообщение о ошибке, чтоб юзер знал, что мы принимаем лишь файлы изображений. Если проверка прошла удачно, мы перебегаем к обработке файла в функции handleFileUpload, которую сделаем дальше. Обновите index.js:
JavaScript /** * @param {File} file */ function handleFileUpload(file) { const fileReader = new FileReader(); fileReader.addEventListener(«load», (event) => { // Dispatch an event to the profile card containing the updated profile. dispatchCardEvent({ image: event.target.result, }); }); fileReader.readAsDataURL(file);
}
const profileCard = document.querySelector(«.profile-card»);
const CARD_UPDATE_EVENT_NAME = «cardupdate»;
function dispatchCardEvent(data) { profileCard.dispatchEvent( new CustomEvent(CARD_UPDATE_EVENT_NAME, { detail: data, }) );
}
123456789101112131415161718192021222324 | /** * @param {File} file */function handleFileUpload(file) { const fileReader = new FileReader(); fileReader.addEventListener(«load», (event) => { // Dispatch an event to the profile card containing the updated profile. dispatchCardEvent({ image: event.target.result, }); }); fileReader.readAsDataURL(file);} const profileCard = document.querySelector(«.profile-card»);const CARD_UPDATE_EVENT_NAME = «cardupdate»; function dispatchCardEvent(data) { profileCard.dispatchEvent( new CustomEvent(CARD_UPDATE_EVENT_NAME, { detail: data, }) );} |
Мобильное приложение VK научилось продвигать бизнес-страницы
Функция handleFileUpload воспринимает файл в качестве параметра и пробует прочесть файл в качестве URL данных при помощи устройства чтения файла.
Конструктор FileReader простирается от EventTarget, что дозволяет прослушивать события. Событие load запускается опосля загрузки изображения — в нашем случае как URL-адрес данных.
Вы также сможете загружать изображения в остальных форматах. На MDN есть хорошая документация по FileReader API, если вы желаете выяснить больше о считывании файлов.
Опосля загрузки изображения нам нужно показать его в карточке профиля. Для этого мы отправим настраиваемое событие cardupdate в карточку профиля. dispatchCardEvent обрабатывает создание и отправку события в карточку профиля.
Если вы помните из раздела выше, у пользовательских событий есть свойство detail, которое можно применять для передачи данных. В этом случае мы передаем объект, содержащий URL-адрес изображения, приобретенный от программки чтения файлов.
Потом нам нужна карточка профиля для прослушивания обновлений карточки и соответственного обновления DOM.
JavaScript profileCard.addEventListener(CARD_UPDATE_EVENT_NAME, handleCardUpdate); /** * @param {CustomEvent} event */ function handleCardUpdate(event) { const { image } = event.detail; if (image) { profileCard.querySelector(«img»).src = image; }
}
12345678910 | profileCard.addEventListener(CARD_UPDATE_EVENT_NAME, handleCardUpdate);/** * @param {CustomEvent} event */function handleCardUpdate(event) { const { image } = event.detail; if (image) { profileCard.querySelector(«img»).src = image; }} |
Как показано выше, вы просто добавляете прослушиватель событий, как обычно, и вызываете функцию handleCardUpdate, когда событие запускается.
Как применять деструктуризацию объекта в JavaScript
handleCardUpdate получает событие как параметр. Используя деструктуризацию объекта, вы сможете получить свойство image из event.detail. Потом установите атрибут изображения src в карточке профиля как URL-адрес изображения, приобретенный из события. Чтоб разрешить юзерам загружать изображения через поле ввода:
JavaScript const fileInput = document.querySelector(«#file-input»);
fileInput.addEventListener(«change», (event) => { handleFileUpload(event.target.files[0]);
});
12345 | const fileInput = document.querySelector(«#file-input»); fileInput.addEventListener(«change», (event) => { handleFileUpload(event.target.files[0]);}); |
Когда юзер выбирает изображение, событие конфигурации запускается при вводе файла. Мы можем обработать загрузку первого изображения, потому что нам необходимо лишь одно изображение для карточки профиля.
Сейчас нам не надо созодать ничего новейшего, потому что мы разработали весь функционал при добавлении поддержки перетаскивания.
Последующая функция, которую необходимо добавить — это обновление имени и профессии:
JavaScript const nameInput = document.querySelector(«#name»);
const occupationInput = document.querySelector(«#occupation»);
occupationInput.addEventListener(«change», (event) => { dispatchCardEvent({ occupation: event.target.value, }); }); nameInput.addEventListener(«change», (event) => { dispatchCardEvent({ name: event.target.value, });
});
12345678910111213 | const nameInput = document.querySelector(«#name»);const occupationInput = document.querySelector(«#occupation»); occupationInput.addEventListener(«change», (event) => { dispatchCardEvent({ occupation: event.target.value, });});nameInput.addEventListener(«change», (event) => { dispatchCardEvent({ name: event.target.value, });}); |
Для этого мы прослушиваем событие конфигурации и отправляем событие обновления карты, но сейчас с иными данными. Нам необходимо обновить обработчик, чтоб иметь возможность обрабатывать не только лишь изображения.
JavaScript /** * @param {CustomEvent} event */ function handleCardUpdate(event) { const { image, name, occupation } = event.detail; if (image) { profileCard.querySelector(«img»).src = image; } if (name) { profileCard.querySelector(«span.name»).textContent = name; } if (occupation) { profileCard.querySelector(«span.occupation»).textContent = occupation; }
}
123456789101112131415 | /** * @param {CustomEvent} event */function handleCardUpdate(event) { const { image, name, occupation } = event.detail; if (image) { profileCard.querySelector(«img»).src = image; } if (name) { profileCard.querySelector(«span.name»).textContent = name; } if (occupation) { profileCard.querySelector(«span.occupation»).textContent = occupation; }} |
Обновите функцию handleCardUpdate, чтоб она смотрелась как в приведенном выше фрагменте. Тут мы опять используем деструктуризацию объекта, чтоб получить изображение, имя и род занятий из event.detail. Опосля получения данных мы отображаем их на карточке профиля.
Заключение
Время от времени легче осознать код, когда вы думаете о нем исходя из убеждений отправляемых событий — как пользовательских, так и нативных событий DOM. Пользовательские события JavaScript могут сделать лучше взаимодействие с юзером вашего приложения при правильном использовании. Потому логично, что они включены в некие из ведущих фреймворков JavaScript, таковых как Vue.js (во Vue вы отправляете пользовательские события при помощи $emit). Код демонстрации, использованный в этом руководстве, доступен на GitHub.
Создатель: James James
Редакция: Команда webformyself.
Источник
Вам также может понравиться