enter,submit,button, 提交表单的问题
update

刚刚发现我对事件的理解有一个巨大的错误观念. 在事件处理函数中return false的意义到底是什么? 特别是涉及到keydown keypress keyup, 而且是在表单中, 更麻烦的是当按键是Enter键的时候.

因为观察到keydown的返回值会对keypress产生影响, 我以为keydown keypress keyup这是一个事件传递的链条, 任何一个返回false, 后面的事件就不会触发. 实际上完全不是这样, 事件传递的真实含义是同一个事件在不同节点上的传递, 也就是冒泡, 而不是两个事件之间的传递, 所以keydown中返回false 不会对keyup造成任何影响.

一个事件发生的时候可以用两种方式执行"阻止", 一个是preventDefault, 是阻止该事件的默认行为, 一个是stopPropagation, 是阻止事件冒泡. 而两个不同的事件之间没有阻止的概念. 这里面最特殊的是keypress, 猜想keypress和keydown keyup有本质的不同, 他可能不是一个独立的事件, 而是keydown事件的默认行为的一部分, keydown返回false阻止了默认行为, 因此而影响到keypress, 而keyup是独立的事件, 不受keydown的返回值的影响.

如果一个表单中有submit按钮, 那么当按下Enter键的时候, keypress对表单的提交也是有影响的, 大致的猜想是 keydown的默认行为触发keypress事件, keypress的默认行为中可能会检测按键是否是Enter键, 如果是则触发submit按钮的click事件, submit的click事件的默认行为中则会触发表单的submit事件, 从而提交表单. 所以keydown ,keypress ,submit click ,submit 这一系列事件才是一个链条, 而且是默认行为的链条. 注意是同一个事件的默认行为的链条, keyup不在这个链条上, 他是独立产生的.

因为要做一个注册的页面, 就跑到一些网站观察其注册页面的javascript. 刚好经常用百度, 顺手打开百度的注册页面, 在这个过程中碰到一个怎么也想不明白是现象: 无法用Enter键触发submit事件. 就为这件事情, 几乎费去一天. 虽然最终发现是一个极度简单的问题, 不过这个过程中澄清了不少疑问.

一开始我以为Enter无法submit是通过在事件中返回false的方法来做到的. 但是看里面的代码完全看不出来, 越看越模糊. 于是我用Jquery写一段代码来测试Enter与表单提交到底是怎么运作的.

function showmsg(msg){
    
    $('body').append("<p>"+msg+"</p>");
}

$('#login-form').submit function(){
    showmsg('gonna submit');
    return false;
}

$('button[type=submit]').click(function () {
    showmsg('clicke submit');
    //this.form.submit();
    return
});


$('#email').keydown(function(){
    showmsg('first keydown');
    return false;
    
});

$('#email').keydown(function(){
    showmsg('second keydown');
    return true;
});

$('#email').keypress(function(){
    showmsg('second keypress');    
    
    
});

$('#email').keyup(function(){
    showmsg('second keyup');
});

测试的结果表明, 事件流程是这样: keydown -> keypress -> click on submit -> submit. 期间如果任何一个事件返回false, 则后面的事件不会执行.

同时注意到百度那个js代码中的事件处理函数里面有些根本没有return语句, 因此也测试了没有return语句的情况. 经过测试如果不写return语句效果和return true一样. 不过注意函数如果没有return语句, 实际上返回值是'undefined', 做布尔运算结果会是false.

然后又用百度的事件绑定函数试了一下, 结果更加奇怪, 无论返回什么值, Enter键都会提交表单.

function showmsg(msg){
    baidu.dom.insertHTML(document.body'beforeEnd',"<p>"+msg+"</p>");
    
}




baidu.event.on('login-submitbutton','click',function(){
    showmsg('clicke submit');
    //this.form.submit();
    
    alert('ss');
})


baidu.event.on('email','keydown',function(){
    showmsg('first keydown');
    
});


baidu.event.on('email','keydown',function(){
    showmsg('second keydown');
    
});


baidu.event.on('email','keypress',function(){
    showmsg('second keypress');
    
});

baidu.event.on('email','keyup',function(){
    showmsg('second keyup');
    alert('keyup');
});

百度的那个tangram库到底是怎么绑定事件的? 答案在这里

baidu.event.on function(eleIdeventnamelistener) {
    eventname eventname.replace(/^on/i"");
    eleId baidu.dom._g(eleId);
    
    //实际绑定的是这个事件
    //所以事件的返回值永远是g的返回值, 永远是true
    var function(j) {
        listener.call(eleIdj)
    }, 
    _listeners baidu.event._listeners
    _eventFilter baidu.event._eventFilter
    i
    eventname;
    eventname eventname.toLowerCase();
    if (_eventFilter && _eventFilter[eventname]) {
        _eventFilter[eventname](eleIdeventnameg);
        i.type;
        i.listener
    }
    
    // 实际注册的全部是函数g, g永远都是no return
    if (eleId.addEventListener) {
        eleId.addEventListener(cgfalse)
    else {
        if (eleId.attachEvent) {
            eleId.attachEvent("on" cg)
        }
    }
    _listeners[_listeners.length] = [eleIdeventnamelistenergc];
    return eleId
};

用这个方法绑定的事件没有直接绑定事件处理函数, 而是加了一个包装函数, 这个函数没有return语句, 也就是说这样绑定的事件永远都会返回true, 永远不会阻塞后面的事件. 在事件处理函数里面无论返回什么都没有意义.

基本可以断定不是javascript的问题, 于是将HTML和正常的表单做对比. 在最后一行, 看到下面一行

      <input class="pass_reg_submit" id="pass_reg_submit_0" type="button" value="注册">

注意type是button, 而不是submit, 这个表单根本没有submit按钮! 所以Enter键提交表单的原理是, 找到form中的submit按钮然后触发其click事件, submit按钮的click事件的默认动作就是提交表单. 现在根本就没有submit按钮, 当然Enter键就完全无用.

几乎所有网上的防止Enter提交表单的方法都是监视keyCode为13的键盘事件, 其实更简单的办法是不要使用submit按钮, 用a标签或者是button代替, 添加click事件, 然后在需要的地方触发click事件即可.