对焦被触发两次

问题描述 投票:0回答:4

我有一个文本框和一个 Jquery UI 对话框。当用户在文本框中输入完毕并按 Enter 后,我想显示该对话框。为了实现这一点,我使用以下代码:

$(document).ready(function () {
    var helpDial = $('#helpDialog');
    var input = $('#helpSearch');

    helpDial.dialog({
        width: 800,
        autoOpen: false,
        modal: true,
        title: "Templates",
        position: [165, 158]
    });

    input.focusin(function () {
        helpDial.dialog('close');
    }).focusout(function () {
        helpDial.dialog('open');
    }).on('keypress', function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 13) {
            input.focusout();
            return false;
        }
    });
});

<input id="helpSearch" />
<div id="helpDialog"></div>

http://jsfiddle.net/7Fpm4/1

问题是,当我按 Enter 时,

focusout
会被调用两次,一次是从
input.focusout()
调用,第二次是在
helpDial.dialog('open')
事件处理程序中的
focusout
之后调用。这会导致创建两个背景叠加层,当我关闭对话框时,一个叠加层仍然可见。

我做错了什么?有没有更好的方法来处理这种情况——“在文本字段中按下回车键会打开一个 jQuery 对话框”。谢谢。

jquery jquery-ui jquery-ui-dialog
4个回答
6
投票

防止事件触发的唯一方法是解除事件处理程序的绑定。或者,根据情况,根据事件触发时可用的信息采取不同的行动。

只要元素失去焦点,就会触发

focusout
事件。在这种情况下,每次用户单击文本框时,都会触发
focusin
事件。一旦光标离开文本框(打开对话框时发生),就会触发
focusout
事件。

您的代码的问题在于,您强制调用了

focusout
事件,然后当您打开对话框时,自然会调用
focusout
事件。因此,请按如下方式更改代码:

$(document).ready(function () {
    var helpDial = $('#helpDialog');
    var input = $('#helpSearch');

    helpDial.dialog({
        width: 800,
        autoOpen: false,
        modal: true,
        title: "Templates",
        position: [165, 158]
    });

    input.on('focusin', function () {
        input.on("focusout", textboxFocusOut);
    }).on('keypress', function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 13) {
            textboxFocusOut();
        }
    });

    function textboxFocusOut() {
        input.off("focusout", textboxFocusOut);
        helpDial.dialog('open');                
    }

});

http://jsfiddle.net/8L7EL/1/

此代码的作用是将函数绑定到

 
focusout handler
 中的 
focusin 。如果用户离开文本框,将调用
focusout
事件处理程序,这会立即取消绑定
focusout
事件(以防止多次绑定该函数)。如果用户按下 Enter 键,则会手动调用该函数,这会在打开对话框之前删除
focusout
事件处理程序,以防止在对话框打开时自动触发
focusout
事件。


3
投票

最明显的解决方案可能是使用像

enter_pressed
这样的变量来通知
focusout
函数:

$(function () {
    var helpDial = $('#helpDialog'),
        input = $('#helpSearch'),
        enter_pressed = false;

    helpDial.dialog({
        width: 800,
        autoOpen: false,
        modal: true,
        title: "Templates",
        position: [165, 158]
    });

    input.on('focusout', function () {
        if( !enter_pressed ) {
            helpDial.dialog('open');
        } else {
            enter_pressed = false;
        }
    }).on('keypress', function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 13) {
            enter_pressed = true;
            helpDial.dialog('open');
        }
    });
});

http://jsfiddle.net/joplomacedo/7Fpm4/7/

但是,我相信有一个更清洁的解决方案。我会尝试想出它。

旁白
真的需要 .focusin 事件处理程序吗?


0
投票

http://jsfiddle.net/7Fpm4/2/我更新了你的示例,只是将 input.focusin(function () 更改为 input.change(function ()


0
投票

我想在我无法访问 focusout 事件处理程序的地方触发 focusout 事件,因此我不能只调用该函数。

我解决这个问题的方法是创建一个虚拟的可聚焦输入字段,聚焦它然后将其删除。这会导致 focusout 事件仅被触发一次。

// Create a focusable dummy input element
let dummyInput = document.createElement('input');
document.body.appendChild(dummyInput);

// Triggers focusout event
dummyInput.focus();

// Remove the dummy input element
document.body.removeChild(dummyInput);
© www.soinside.com 2019 - 2024. All rights reserved.