今天写网页碰到一个问题。
给按钮添加点击事件,然后跳转到其他网页,写完代码在firefox上测试通过后部署,却在手机上测试发现了问题,按钮点了之后根本没反应。想起浏览器是chrome,于是打开电脑上的chrome调试,发现同样没有反应。
html页面表单代码
1 | <form class="form-signin" action="#"> |
监听事件代码
1 | $("#btn-search").click(function(){ |
start函数,执行跳转操作
1 | var start = function(content){ |
基本确定是代码问题,于是搜索为什么chrome下window.location.href没反应,找了好几个地方,终于解决了问题:在处理事件末尾加上return false。
window.location.href无效/不跳转的原因分析
问题虽然解决了,但是仍然不知道为什么(web野路子伤不起啊)。本着打破沙锅问到底的精神,又一阵查找。看那篇文章似乎指的是JS的冒泡事件引起的,于是就从JS冒泡开始研究起。
事件的发生顺序
这个问题的起源非常简单,假设你在一个元素中又嵌套了另一个元素
| element1 |
| ————————- |
| |element2 | |
| ————————- |
| |
:并且两者都有一个onClick事件处理函数(event handler)。如果用户单击元素2,则元素1和元素2的单击事件都会被触发。但是哪一个事件先被触发?哪一个事件处理函数会被首先执行?换句话说,事件的发生顺序到底如何?
两种模型
不出所料,在那些“不堪回首”(浏览器大战)的日子里,Netscape和微软有两种截然不同的处理方法:
Netscape主张元素1的事件首先发生,这种事件发生顺序被称为捕获型
微软则保持元素2具有优先权,这种事件顺序被称为冒泡型
这两种事件顺序是截然相反的。Explorer浏览器只支持冒泡事件,Mozilla,Opera7和Konqueror两者都支持。而更古老的opera和iCab两者都不支持
冒泡型事件
当你使用冒泡型事件时
/ \
—————| |—————–
| element1 | | |
| ———–| |———– |
| |element2 | | | |
| ————————- |
| Event BUBBLING |
:元素2 的处理函数首先被触发,元素1其次
(摘自 生动详细解释javascript的冒泡和捕获,包懂包会)
也就是说事件并不是仅执行了一个函数,而是继续向上传递,引起了其他事件。
拿我的例子做个说明。
首先,点击按钮触发自定义的监听事件,监听事件调用了start函数(打log发现确实执行了,但是没有跳转页面),然后告诉浏览器跳转页面。这里有一个问题,浏览器没有立即跳转(不然也没有那么多事了),而是先解析、连接目标网站,连接上之后才真正跳转,应该是浏览器为了避免用户长时间面对空白屏幕而做的优化。
准备跳转的同时,原网页的代码仍然可以执行,于是冒泡模型继续触发默认的事件:表单的submit事件,而表单的ACTION是“#”(本网页),于是浏览器就停止了跳转(事实上,它还没来得及发出解析请求)。
就这样,造成了submit按钮点击无反应的假象。
知道了原因,那么解决方案也就很简单,制止它的默认事件。在监听事件末尾加上return false即可
return false可以且仅可以阻止默认的事件,e.stopPropagation()可以取消所有冒泡事件,这样,子元素的事件就不会引起父元素的监听事件。
关于阻止冒泡,可以参考:浅谈 javascript 事件取消和阻止冒泡
以后一定要记得多加这么一句,不然真是坑死人。话说我的某一个网站也是这原因导致反馈请求无法处理(我说这学期改版后怎么一直没人反馈呢,汗)