【问题标题】:Exporting a function from an already exported function从已导出的函数中导出函数
【发布时间】:2021-03-01 00:46:41
【问题描述】:

我正在做一个项目,使用 Nodejs 作为后端,使用 Parcel Bundler 编译的 vanilla JS 用于客户端 JS 和 PUG 模板引擎来生成视图。

请注意,我还使用 FullCalendar v5 插件。我认为这无关紧要,因为我觉得没有它可能会发生这种情况,但仍然是我目前遇到这个问题的原因。

让我们直奔主题:我有一个名为initCalendar() 的“主”父函数。 它初始化日历,创建 FullCalendar 实例(以及所有日历方法),根据给定的配置设置它并在视图上呈现它。这个函数是events.js 的顶层函数,我喜欢称之为“main”函数。

initCalendar() 使用 export 关键字从 events.js 导出:export const initCalendar = () => { … }

在此之后,我编写了日历专有功能,允许我根据日历上的操作执行我想要的任何操作。比如eventClick(),只要点击日历中的一个事件就会执行,正如它的名字所暗示的那样。

重点是,我在这个eventClick() 函数中创建了一些函数(它本身在initCalendar() 中),其中一些我需要在index.js 中使用。因此需要将它们导出。另外,我不能将这些函数移到initCalendar() 范围之外,因为我会丢失我的函数正常运行所需的重要变量,并且我想避免使用全局变量。

我的自定义函数嵌套如下:initCalendar() -> eventClick() -> myFunction()(“主”导出父函数 -> 中间日历函数 -> 我的函数(要导出))。

如果您想知道为什么我必须这样做,它是为了保持我迄今为止对项目的所有客户端 JS 使用的相同工作流程,尝试“包裹方式” .我有很多从许多不同文件导入到index.js 中的导出函数,但是这个问题只有在我将 FullCalendar 包含在其中时才出现。

所以我现在找到的解决方案是直接从eventClick() 导出我的函数,这次使用exports 关键字:exports.myFunction = myFunction。这样做之后,我可以将它们导入 index.js 并继续使用我用于所有客户端 JS 的相同工作流程(请记住,使用 Parcel Bundler 编译)。

您如何看待这种“技术”?从已经导出的父函数中导出子函数不是不好的做法吗?

对我来说这似乎很老套,我不太喜欢这样……但我还没有找到更好的解决方案。 也许有人可以给我一些关于这样做是否可以的见解,如果不行,如何以另一种方式解决问题?我想也许可以使用回调函数,但我无法做到以这种方式工作。

------- 编辑:一些代码-------

这是一些代码。我试图将它缩减到最少,因为clickEvent() 函数的代码实际上有数百行,而 FullCalendar 的代码则更大。

events.js :如您所见,eventClick() 函数首先打开一个 Modal,其中包含所有事件信息(我没有写,因为不相关)和一个删除点击事件的按钮。

这个按钮应该让他的listener 设置为index.jsclick 事件上调用“导出的子函数”removeEvent(),以从数据库和日历中删除关联的事件。

里面还有其他相同风格的功能,但是这个应该足以明白我在说什么了。

// 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();
        }
    });
}

非常感谢

【问题讨论】:

  • 我建议您添加更多的代码,而不仅仅是文字。这样更容易快速找到问题。除此之外,您能否添加足够的代码来说明原因:“我无法将这些函数移出 initCalendar() 范围,因为我会丢失我的函数正常运行所需的重要变量”我>
  • @maazadeeb 我想这样做,但实际上有大量代码......我会尽量减少它并更新帖子。
  • @maazadeeb 好了,我添加了一些相关代码
  • 为什么不能在创建模态时给delete-event按钮添加点击处理程序?从共享代码的外观来看,您的Modal 应该有一个onRemoveButton 属性,应该附加到您现在正在编写的removeEvent 函数。我不明白你为什么需要导出它。

标签: javascript fullcalendar parceljs


【解决方案1】:

发表我的评论作为答案,因为我相信这是解决这个问题的正确方法。

您应该在创建模式时向delete-event 按钮添加点击处理程序。

此外,从共享代码的外观来看,您的 Modal 应该有一个 onRemoveButtonClicked 属性,应该分配给您现在正在编写的 removeEvent 函数。我不明白你为什么需要导出它。

【讨论】:

  • 感谢您的回答。但是,我已经尝试直接在 delete-event 按钮上使用单击处理程序,但由于事件传播,它无法按预期工作。如果我使用event.stopImmediatePropagation() 它可以工作,但我觉得这不好。不是吗?此外,我的 Modal 类是通用的,并且在很多地方都使用过。这个delete-event 按钮仅在“this”模式中(从events.js 中的evenClick() 函数填充的那个),所以我想在类中添加一个属性,该属性将仅用于几十个函数中的一个函数用的不是很好。你怎么看?
  • 另外,我尝试编写这种“包裹方式”,如果我理解正确的话,其中一部分是将侦听器(在 index.js 中)与函数(在任何其他文件中)分开)。我已经成功地在 eventClick() 函数中编写了所有代码,包括侦听器等,但随后我松散了我认为有用且干净的这种“代码分离”(您可以在一个地方对所有侦听器进行概述 - index.js - 你可以很容易地找到一个听众正在调用的函数)。或者,也许我不理解我所说的编码的“包裹方式”?
  • 另外,通过直接在eventClick()(监听器等)中编码所有内容,我遇到了很多事件传播问题。这意味着我需要使用evt.stopImmediatePropagation() 或做很多if (evt.target === someEl) return; 来防止它。如前所述,我不喜欢使用stopPropagation() 并且使用所有if (evt.target === …) return 代码变得比需要的大而且丑陋。我认为这些事件传播问题来自 FullCalendar,因为它在所有地方都使用了侦听器,所以我的点击事件也可以到达它们。我在不使用 FullCalendar 的文件上没有这个问题
  • @Tom687 这是什么“包裹”方式?为什么捆绑器会规定您如何编写业务逻辑?我无法深入了解您的问题中未提及的细节。但是对于一个模态来说,拥有onButtonClick 或任何需要的东西是很常见的。如果它没有通过,也许你没有显示那个按钮。那里有很多通用的Modal,我建议你看看它们。
  • 实际上我不确定这种“包裹方式”,但它似乎是我从使用此捆绑器的项目中看到的一种模式。无论哪种方式,我都喜欢将侦听器与函数分开的事实。关于模态,我真的不明白我将如何使用 onButtonClick 属性?像if (modal.buttonClick) { callFunction() } 吗?另外,如果模态包含 3 个按钮(这个实际上有 3 个)应该是什么?顺便说一句,我用这个类创建的所有模式都有不同类型的按钮。非常感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-28
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 2022-11-12
  • 1970-01-01
  • 2013-02-28
相关资源
最近更新 更多