繁体   English   中英

当事件仅发生一次时,JavaScript事件被触发两次

[英]JavaScript event is being fired twice when event has only happened once

我一直在研究一个小的JavaScript库,该库用于处理简单的触摸事件,例如点击和滑动。 我暂时将其放置在GitHub上。

在此处查看:thumb.js-存储库

如果您查看thumb.html ,您可以看到我如何使用我的库。

//JavaScript portion
//Assign the tap event to all elements with specific classname
thumb.get('.swipearea').on('tap', function(e) {
    console.log('The event "' + e.detail.name + '" occured.')
})

//Assign the swipeleft event by ID
thumb.get('#a1').on('swipeleft', function(e) {
    console.log('The event "' + e.detail.name + '" occured.')
})

正如您从HTML文件中看到的那样,我为所有名称为“ swipearea”的元素分配了“ tap”。 但是,我只想向具有相同类名的一个元素添加“ swipeleft”事件,因此我使用该元素的ID附加了该事件。

这在大多数情况下都是有效的。 问题是,当我点击带有两个事件的元素时,它将消息记录两次。 向左滑动时,它还会记录两次。 但是,当我点击另一个只分配了“ tap”的元素时,它一次正确地登录到控制台。

我是否错误地创建了每个实例? 我试图在thumb实例之外创建一个方法,但这导致了相同的行为。

如何消除这种行为?

有关控制台日志的更多信息

当我在ID为a1的元素上点击一次时,我得到The event "Tap" occurred. 登录到控制台两次。

当我在ID为a1的元素上The event "Swipe Left" occurred.我得到The event "Swipe Left" occurred. 登录到控制台两次。

当我在ID为a2的元素上点击一次时,我得到The event "Tap" occurred. 1次登录到控制台。

您的代码的结构很有可能会使得侦听器被添加两次。 我们需要查看更多代码才能确定。

在某些环境中,将不再添加与上一个监听器完全匹配的监听器(在===意义上)(本机addEventListener API也是这种情况)。 我不知道jQuery是否是这种情况。 要尝试此操作,可以将侦听器定义为单独的函数:

function listener(e) {
    console.log('The event "' + e.detail.name + '" occured.');
}

然后将其添加为

thumb.get('.swipearea').on('tap', listener);

您可能会问,即使我在源代码中添加了两次侦听器,侦听器函数代码也完全相同,这并不意味着该函数是相同的,因此不会将其添加为重复项。听众? 好吧,不。 如果该函数在其他函数中定义,则每次都会是“不同”函数。 考虑以下:

function am_i_the_same() {
    return function() {return 42;};
}
am_i_the_same() === am_i_the_same(); // false

如果您在面向对象的环境中工作,则可以执行以下操作

my_object = {
    tap_listener: function(e) {
        console.log('The event "' + e.detail.name + '" occurred.');
    },
    set_listener: function() {
        thumb.get('.swipearea').on('tap', this.tap_listener);
    }
};

但是,例如,在执行this.tap_listener.bind(this)那一刻,您现在每次调用时都有一个不同的函数,因此将导致重复的侦听器。

更新

首先,我不会预先构建您的自定义事件。 每当您需要发射它时,我都会创建一个新的。 否则,您可能会与时间戳,目标元素和传播设置发生奇怪的冲突。

说到传播设置,最好在所有触摸事件上立即停止传播。

接下来,这可能是个人喜好,但我不会像您那样建立多元素支持。 所有这些循环以及forEach和maps会使您的代码复杂化。 只需编写一个组件即可完成一项任务,即管理触摸,而不是完成两项任务,即管理触摸和管理元素组。

我很好奇为什么在全局范围而不是在使用它们的函数中声明像distanceX这样的变量。

至于您的特定问题,我看不到为什么发生,但是我会尝试在thumb.js的第112行添加else ,并查看是否出于某种原因构造了if语句以便允许tap和swipe事件被省略。

我想您知道那里有图书馆以此为生。 他们将在许多小细节上做得更好,例如在touchstart不在应用程序区域之外时,诸如touchend的边缘情况就会出现在您的元素上,等等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM