关于自动完成:jQuery无法使用event.stopPropagation,event.preventDefault返回返回键事件的表单提交并返回false

jQuery unable to stop form submission on return key even with event.stopPropogation, event.preventDefault and return false

我刚刚使用jquery构建了一个自定义自动完成组件。我的问题是,当有人使用键盘上/下箭头键选择一个自动完成建议并点击返回时,即使我调用event.stopperopogation()和event.preventDefault(),也会发生表单提交,并返回false。

我已经将核心函数绑定到keyup事件:

1
$('#'+id).keyup(function(event){ getResults(event,this,url,method,data,setEl,makeLink,cssClass); event.preventDefault(); event.stopPropagation(); return false;});

getresults对返回JSON对象的服务器脚本进行Ajax调用。getresults伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
function getResults(event,element,url,method,data,setEl,makeLink,cssClass) {
    $(element).css("position","inherit");
var keyCode = event.keyCode ? event.keyCode : event.which;
if (keyCode == 40){ //down arrow key
    if ($("#ac_"+element.id+" .hover").is("li")) { // some li is already on hover!
        if ($("#ac_"+element.id+" .hover").is($("#ac_"+element.id+" li").last())) {
            $("#ac_"+element.id+" .hover").removeClass("hover");
            $("#ac_"+element.id+" li").first().addClass("hover");
        } else {
            $("#ac_"+element.id+" .hover").removeClass("hover").next().addClass("hover");
        }
    } else {
        $("#ac_"+element.id+" li").first().addClass("hover");
    }
    event.stopPropagation();
    event.preventDefault();
    return false;
} else if (keyCode == 38){ //up arrow key
    if ($("#ac_"+element.id+" .hover").is("li")) { // some li is already on hover!
        if ($("#ac_"+element.id+" .hover").is($("#ac_"+element.id+" li").first())) {
            $("#ac_"+element.id+" .hover").removeClass("hover");
            $("#ac_"+element.id+" li").last().addClass("hover");
        } else {
            $("#ac_"+element.id+" .hover").removeClass("hover").prev().addClass("hover");
        }
    } else {
        $("#ac_"+element.id+" li").last().addClass("hover");
    }
    event.stopPropagation();
    event.preventDefault();
    return false;
} else if (keyCode == 13){ //return key
    if ($("#ac_"+element.id+" .hover").is("li")) { // some li is already on hover!
        $("#ac_"+element.id+" .hover").removeClass("hover").trigger("click");

    }
    event.stopPropagation();
    event.preventDefault();
    return false;
}

if (setEl) { if (!$(element).val() || $(element).val()=="") { $("#"+setEl).val('');} }
if ($(element).val() != autocomplete_prev_search[element.id]) {
    $("#ac_"+element.id).remove();
}
autocomplete_prev_search[element.id] = $(element).val();
if ($(element).val().length>=3) {
    if (!url){return;}
    if (!data) {
        data = {match:$(element).val()};
    } else {
        data.match = $(element).val();
    }
    if (!method) { method ="POST"; }
    $.ajax({
        type: method,
        url: url,
        data: data,
        success: function(result){ return resultHandler(result,element.id,setEl,makeLink,event); },
        beforeSend: function(){ $(element).css("background-image","url('/kit/icons/indeterminate.gif')").css("background-repeat","no-repeat").css("background-position","right center"); },
        complete:function(){ $(element).css("background-image","none"); },
        error: errorHandler,
        timeout: 1000,
        dataType:"json"
    });
}
    return false;
}

最后,Ajax调用的成功处理程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function resultHandler(result, id, setEl, makeLink, event) {
    $("#ac_"+id).remove();
if (result && result.length>0) {
    var $ul = $("<ul id='ac_"+id+"' class='autocomplete'>
</ul>
");
    var $li;
    for (var i=0; i<result.length; i++) {
        if (result[i]) {
            if (makeLink) {
                $li = $("<li onclick="location.href='/"+result[i].type+"/"+result[i].id+"'">"+result[i].type+" '"+result[i].title+"'
</li>
");
            } else {
                if (!setEl) {
                    $li = $("<li onclick="$('#"+id+"').val('"+result[i].id+"'); return killEvent(event);">"+result[i].type+" '"+result[i].title+"'
</li>
");
                } else {
                    $li = $("<li onclick="$('#"+setEl+"').val('"+result[i].id+"'); $('#"+id+"').val('"+result[i].title+"');return killEvent(event);">"+result[i].type+" '"+result[i].title+"'
</li>
");
                }
            }
            //$li.click(function(){ location.href="/"+result[i].type+"/"+result[i].id; });
            // doesn't work as the click function has no access to result[i] object
            $ul.append($li);
        }
    }
    var left = $('#'+id).offset().left;
    var top = $('#'+id).offset().top+$('#'+id).outerHeight();
    $ul.css("width",$("#"+id).css("width")).css("left",left+"px").css("top",top+"px");
    $ul.insertAfter('#'+id);
}
    return false;
}

最后,killevent是一个简单的函数:

1
2
3
4
5
6
7
8
function killEvent(event) {
    var keyCode = event.keyCode ? event.keyCode : event.which;
if (keyCode == 13) {
    event.stopPropogation();
    event.preventDefault();
    return false;
    }
}

因此,所有的处理程序,甚至是自动完成建议列表的li元素都返回了false,并调用stopperopogation和preventdefault。但是,表单提交仍然会发生!我在这里做错了什么或是错过了什么。对不起,这封长信!


好吧,我找到了一种方法,在使用键盘的上/下键选择自动完成建议并输入时,当按下返回键时,停止浏览器的默认事件!

1
2
$('#'+id).keydown(function(event){ return handleKey(event); });
$('#'+id).keyup(function(event){ return getResults(event,this,url,method,data,setEl,makeLink,cssClass); });

在keydown上,handlekey函数只检查keycode 13,然后调用stoppropagation和preventdefault!

这是手持钥匙的功能

1
2
3
4
5
6
7
8
9
10
function handleKey(event) {
    var keyCode = event.keyCode ? event.keyCode : event.which;
    if (keyCode == 13) {
        event.preventDefault();
        event.stopPropagation();
        return false;
    } else {
        return true;
    }
}

因此,我取消了浏览器的默认操作键!在keyup上,getresults只检查并返回是否有选择!

诀窍是,要停止浏览器的默认操作,我们必须对keydown而不是keyup执行操作!

特别感谢克罗诺斯指出这一点!


不处理键向上事件,而是处理提交事件。在那里添加一个签入以确保所有内容都完整,如果不完整,则返回false。