【问题标题】:jQuery's One - Fire once with multiple event typesjQuery's One - 使用多种事件类型触发一次
【发布时间】:2014-08-26 15:58:56
【问题描述】:

有没有办法在引发任何事件时触发单个函数?

例如,如果我有以下函数:(demo in jsfiddle)

$('input').one('mouseup keyup', function(e){ 
    console.log(e.type);
});

我只想调用该函数一次,不管是哪个事件触发了它。

但是根据docs换成.one():

如果第一个参数包含多个以空格分隔的事件类型,则事件处理程序为每个事件类型调用一次。

因此,目前该函数将为每种事件类型触发一次。

【问题讨论】:

    标签: javascript jquery events


    【解决方案1】:

    不要使用.one,而是使用.on 并使用.off 手动删除绑定。

    $('input').on('mouseup keyup', function(e){
        console.log(e.type);
        $(this).off('mouseup keyup');
    });
    

    小提琴:http://jsfiddle.net/23H7J/3/


    这可以通过命名空间更优雅地完成:

    $('input').on('mouseup.foo keyup.foo', function(e){
        console.log(e.type);
        $(this).off('.foo');
    });
    

    这允许我们使用单个标识符 (foo) 来删除任意数量的绑定,并且我们不会影响该元素可能具有的任何其他 mouseup 或 keyup 绑定。

    小提琴:http://jsfiddle.net/23H7J/41/

    【讨论】:

    • 我的头脑和培根都得救了!太感谢了。将 .off 与多个转换事件一起使用会扭曲我的瓜,因为它正在为每个事件触发(请注意自读文档全文)。
    【解决方案2】:

    很好的答案!要将它们包装成一个函数,这是一个基于当前答案的 jQuery 扩展:

    //The handler is executed at most once per element for all event types.
    $.fn.once = function (events, callback) {
        return this.each(function () {
            $(this).on(events, myCallback);
            function myCallback(e) {
                $(this).off(events, myCallback);
                callback.call(this, e);
            }
        });
    };
    

    然后这样调用:

    $('input').once('mouseup keyup', function(e){ 
        console.log(e.type);
    });
    

    Demo in fiddle

    奖励:这具有额外的好处,即仅通过传入original handler to the off function 来分离此特定函数的处理程序。否则,您将需要自定义命名空间。

    另外,如果您希望处理程序在任何元素触发任何事件时仅触发一次,然后立即分离自身,则只需从扩展名中删除 each,例如这个:

    //The handler is executed at most once for all elements for all event types.
    $.fn.only = function (events, callback) {
        var $this = $(this).on(events, myCallback);
        function myCallback(e) {
            $this.off(events, myCallback);
            callback.call(this, e);
        }
        return this
    };
    

    【讨论】:

    • 你能修改你的函数以使用你的anwser中显示的语法以及$('#someParent').once('keyup etc', '.someChildrenOfParent'), function(e){ doStuff(); });的语法吗?
    • @Drew,就像使用委托一样?可能,想先试试看?
    • 这就是我所拥有的,但我不确定在哪里粘贴“范围”,因此这些函数的行为类似于 jQuery 的 .one()。 jsfiddle.net/wyeq0h3g
    • 嗯,我不确定原始解决方案是否有效,因为我希望橙色背景在此测试小提琴中的每个按键都打开/关闭:jsfiddle.net/L5uzkwv2
    【解决方案3】:

    要开火一次并继续开火,可以使用以下sn-p:

    https://jsfiddle.net/wo0r785t/1/

    $.fn.onSingle = function(events, callback){
        if ("function" == typeof(callback)) {
            var t = this;
            var internalCallback = function(event){
                $(t).off(events, internalCallback);
                callback.apply(t, [event]);
                setTimeout(function(){
                    $(t).on(events, internalCallback);
                }, 0);
            };
            $(t).on(events, internalCallback);
        }
        return $(this);
    };
    

    它的工作原理是使用internalCallback 函数暂时禁用事件,然后异步 (setTimeout) 再次启用它。

    此线程中的大多数其他建议禁用目标上的所有未来事件。然而,虽然 OP 似乎对以前的答案感到满意,但他的问题并没有提到永久禁用事件。

    【讨论】:

      【解决方案4】:

      您可以在函数末尾添加$('input').off();。

      【讨论】:

        【解决方案5】:

        触发一次但继续触发后续更改的更简单方法是临时存储先前的值并进行快速比较:如果没有任何更改,则不要运行函数的其余部分。

        jQUERY

        $('input').on('keyup paste input change', function(e){ 
            var oldValue = $(e.target).data('oldvalue');
            var newValue = $(e.target).val();
        
            if (oldValue === newValue) //nothing has changed
                return;
        
            $(e.target).data('oldvalue',newValue); //store the newly updated value
        
            //proceed with the rest of the function
        });
        

        请注意,我使用.on 来附加事件,而不是.one

        纯 JAVASCRIPT

        对于纯 JavaScript 解决方案,需要单独添加侦听器,因为不可能将多个事件传递给 .addEventListener。

        var selector = document.querySelector('input')
        selector.addEventListener('keyup', updateElement);
        selector.addEventListener('paste', updateElement);
        selector.addEventListener('input', updateElement);
        selector.addEventListener('change', updateElement);
        
        function updateElement(e){
            var oldValue = e.target.getAttribute('oldvalue');
            var newValue = e.target.value;
        
            if (oldValue === newValue) //nothing has changed
               return; 
            console.log (newValue);
            e.target.setAttribute('oldvalue', newValue); //store the newly updated value
        
            //proceed with the rest of the function
        }
        

        假设你想监听输入框的变化,我建议不要使用mouseup来检测可能的右键>粘贴,因为鼠标可以在其他地方释放,不一定在输入框内。为了安全起见,您最好使用keyup、paste、input 和change,就像我在上面的代码中所做的那样。

        【讨论】:

        • 嘿胡安,谢谢分享。我认为这并不能真正回答这里提出的问题。如果我有一个 mouseup 和 keyup 事件并且我只想处理一次,无论哪个被触发,比较 oldValue === newValue 不会让我们到达那里。因此,可能值得记下答案并发布您自己的问题以说明您要解决的问题
        猜你喜欢
        • 2023-02-02
        • 2016-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多