#javascript #fullcalendar #parceljs
#javascript #полный календарь #parceljs
Вопрос:
Я делаю проект, используя Nodejs для серверной части, vanilla JS, скомпилированный с помощью Parcel Bundler для JS на стороне клиента, и движок шаблонов PUG для генерации представлений.
Обратите внимание, что я также использую плагин FullCalendar v5. Я не думаю, что это актуально, поскольку я чувствую, что эта ситуация может произойти и без нее, но, тем не менее, именно по этой причине я сталкиваюсь с этой проблемой в данный момент.
Давайте сразу перейдем к делу: у меня есть вызываемая родительская функция «main» initCalendar()
. Он инициализирует календарь, создает экземпляр FullCalendar (вместе со всеми методами calendars), настраивает его в зависимости от заданных конфигураций и отображает его в представлении. Эта функция является функцией верхнего уровня events.js
, «основной» функцией, как мне нравится ее называть.
initCalendar()
экспортируется с events.js
использованием export
ключевого слова : export const initCalendar = () => { … }
.
После этого я закодировал собственные функции календаря, которые позволяют мне выполнять любые действия, которые я хочу, на основе тех, которые выполняются в календаре. eventClick()
Например, который выполняется всякий раз, когда нажимается событие из календаря, как следует из его названия.
Дело в том, что я создал некоторые функции в этой eventClick()
функции (которая сама находится в initCalendar()
), некоторые из которых мне нужно использовать index.js
. Поэтому необходимо экспортировать их. Кроме того, я не могу переместить эти функции за пределы области initCalendar()
видимости, так как я потеряю важные переменные, необходимые для правильной работы моих функций, и я хотел бы избежать использования глобальных переменных.
Мои пользовательские функции вложены следующим образом: initCalendar() -> eventClick() -> myFunction()
(«основная» экспортируемая родительская функция -> промежуточная функция календаря -> мои функции (для экспорта)).
В случае, если вам интересно, почему я должен делать это таким образом, это сохранить тот же рабочий процесс, который я использовал до сих пор для всех клиентских JS проекта, пытаясь сделать это «способом посылки». У меня есть много экспортированных функций, которые импортируются index.js
из разных файлов, но эта проблема возникла только тогда, когда я включил FullCalendar в микс.
Итак, решение, которое я нашел на данный момент, — экспортировать мои функции напрямую eventClick()
, используя exports
ключевое слово this time : exports.myFunction = myFunction
. Делая это, я могу затем импортировать их index.js
и продолжать использовать тот же рабочий процесс, который я использовал для всех JS на стороне клиента (помните, скомпилированный с помощью Parcel Bundler).
Что вы думаете об этой «технике»? Разве это не плохая практика — экспортировать дочернюю функцию из уже экспортированной родительской функции?
Мне это кажется довольно банальным, и мне это не очень нравится… Но я пока не нашел лучшего решения. Может быть, кто-нибудь мог бы дать мне некоторое представление о том, можно это сделать или нет, а если нет, то как решить проблему другим способом? Я подумал, может быть, использовать функции обратного вызова, но я не могу заставить его работать таким образом.
——- РЕДАКТИРОВАТЬ : Некоторый код ——-
Вот некоторый код. Я постарался сократить его до минимума, потому что код clickEvent()
функции состоит буквально из сотни строк, а код для FullCalendar еще больше.
events.js
: Как вы можете видеть, eventClick()
функция сначала открывает модал, который содержит всю информацию о событии (которую я не писал, потому что она не актуальна) и одну кнопку для удаления события, на которое нажали.
Это кнопка, которая должна быть listener
настроена на index.js
вызов «экспортированной дочерней функции» removeEvent()
для click
события, чтобы удалить связанное событие из базы данных и календаря.
Там есть и другие функции в том же стиле, но этого должно быть достаточно, чтобы понять, о чем я говорю.
// events.js
// … All the es6 imports : { Calendar } - { Modal } - axios; etc …
// As you can see, if I try to export the removeEvent() function from here,
// it would work as exporting goes but I won't have the Modal instance of
// `eventInfoModal` used in `.then()`. Same thing with `const calendar`,
// because they would not be in the scope of `initCalendar()`.
// Therefore I won't be able to call the functions I do on them in `.then()`
export const initCalendar = () => {
const calendarEl = document.getElementById('calendar');
const calendar = new Calendar(calendarEl, {
// … Ton of code to config FullCalendar, import the events, other calendar functions etc…
eventClick: function(eventInfo) {
const eventId = eventInfo.event.id;
const infoModalContainer = document.getElementById('event-info-modal');
// Modal created from an imported class
const eventInfoModal = new Modal(
infoModalContainer,
this.el
);
eventInfoModal.init();
// … Lots of code to populate the modal with the event data, buttons etc …
// So the point here is to call this function from index.js (code of index.js below)
function removeEvent() {
if (confirm('Êtes-vous sûr de vouloir supprimer ce RDV ?')) {
deleteEvent(eventId)
.then(() => {
eventInfoModal.close();
calendar.refetchEvents();
});
}
}
// The "exported child function" I was talking about
exports.removeEvent = removeEvent;
// Then other functions defined and exported the same way, to be used just like removeEvent() in index.js
});
calendar.render();
// Function called from removeEvent() in eventClick() above, just doing an axios DELETE request, no need to write it
async function deleteEvent(eventId) {
}
};
index.js
: Здесь я импортирую все экспортированные функции из других файлов (очевидно, показывая только ту, о которой мы говорим) и пытаюсь сгруппировать и настроить моих слушателей по видам или «по категориям», слушателей, которые затем будут вызывать соответствующие функции, импортированные из других файлов, для выполнения необходимых действий.
// index.js
// … All the es6 imports, including :
import { removeEvent } from './events';
const userEventsPage = document.getElementById('user-events');
if (userEventsPage) {
const deleteEventBtn = document.getElementById('delete-event');
userEventsPage.addEventListener('click', evt => {
if (evt.target === deleteEventBtn) {
removeEvent();
}
});
}
Большое вам спасибо
Комментарии:
1. Я бы посоветовал вам добавить больше кода, чем просто слова. Таким образом, легче быстро найти проблему. Наряду с этим, можете ли вы добавить достаточно кода, чтобы показать причину этого: «Я не могу переместить эти функции за пределы области initCalendar(), так как я потеряю важные переменные, необходимые для правильной работы моих функций»
2. @maazadeeb Я хотел это сделать, но там буквально тонна кода… Я постараюсь сократить это до минимума и обновить пост.
3. @maazadeeb Ну вот, я добавил некоторый соответствующий код
4. Почему вы не можете добавить обработчик щелчка к
delete-event
кнопке при создании модального? Судя по общему виду кода, у васModal
должно бытьonRemoveButton
свойство, которое должно быть привязано кremoveEvent
функции, которую вы пишете прямо сейчас. Я не понимаю, зачем вам нужно ее экспортировать.
Ответ №1:
Публикую свой комментарий в качестве ответа, поскольку я считаю, что это правильный способ решить эту проблему.
Вы должны добавить обработчик кликов к delete-event
кнопке при создании модального элемента.
Кроме того, судя по общему виду кода, у вас Modal
должно быть onRemoveButtonClicked
свойство, которое должно быть присвоено removeEvent
функции, которую вы пишете прямо сейчас. Я не понимаю, зачем вам нужно ее экспортировать.
Комментарии:
1. Спасибо за ваш ответ. Тем не менее, я уже пытался использовать обработчик щелчка непосредственно на
delete-event
кнопке, но из-за распространения событий он работает не так, как ожидалось. Если я используюevent.stopImmediatePropagation()
, это работает, но я чувствую, что это нехорошо. Не так ли? Кроме того, мой модальный класс является универсальным и используется во многих местах. Этаdelete-event
кнопка находится только в «этой» модальной (той, которая заполняется изevenClick()
функции fromevents.js
), поэтому я чувствую, что добавление свойства к классу, которое будет использоваться только в одной функции из десятков, которые она использует, не так хорошо. Что вы думаете ?2. Кроме того, я пытаюсь закодировать этот «способ посылки», одна из частей которого, если я правильно понял, заключается в том, чтобы отделить слушателей (в
index.js
) от функций (в любых других файлах). Я уже успешно написал весь код вeventClick()
функции, включая слушателей и тому подобное, но затем я теряю это «разделение кода», которое я нахожу полезным и чистым (у вас есть обзор всех слушателей в одном местеindex.js
— и вы можете легко найти функцию, которую вызывает один слушатель). Или, может быть, я не понял «способ посылки» кодирования, о котором я говорю?3. Кроме того, кодируя все непосредственно в
eventClick()
(слушатели и тому подобное), у меня возникает множество проблем с распространением событий. Это означает, что мне нужно использоватьevt.stopImmediatePropagation()
или сделать многоеif (evt.target === someEl) return;
, чтобы предотвратить это. Как уже было сказано ранее, мне не нравится использоватьstopPropagation()
, и при использовании всегоif (evt.target === …) return
кода он становится больше, чем нужно, и уродливым. Я думаю, что эти проблемы с распространением событий возникают из-за FullCalendar, потому что он использует слушателей повсюду, поэтому мои события щелчка тоже попадают к ним. У меня нет этой проблемы с файлами, не использующими FullCalendar4. @Tom687 Что это за способ «посылки»? Почему пакетник диктует, как вы пишете свою бизнес-логику? Я не могу вдаваться в подробности, не упомянутые в вашем вопросе. Но для модального очень часто требуется
onButtonClick
или что-то еще. Если она не передана, возможно, вы не показываете эту кнопку. Существует множество общих модальностей, я предлагаю вам взглянуть на них.5. На самом деле я не уверен в этом «способе посылки», но это похоже на шаблон, который я видел в проектах, использующих этот пакет. В любом случае, мне нравится факт отделения слушателей от функций. Что касается модального, я действительно не понимаю, как я буду использовать это
onButtonClick
свойство? Это похожеif (modal.buttonClick) { callFunction() }
? Кроме того, что должно быть, если модальный содержит 3 кнопки (на самом деле у этого есть 3)? Кстати, все модалы, которые я создаю с помощью этого класса, имеют разные виды кнопок. Большое вам спасибо