原由:正常状况下我点击s2时是先弹出我是children,再弹出我是father,可是却出现了先弹出我是father,后弹出我是children的状况,这种状况是在和安卓app交互的h5页面中出现的,本地测试没有问题,可是在安卓打包的内嵌h5页面就出现了问题。简单化的代码先展现出来。javascript
html代码以下html
<div id="father" class="ss1">s1 <div id="children" class="ss2">s2 </div> </div>
事件绑定以下java
$('#father').on('click',function (e) { alert('我是father') }) $('#children').on('click',function (e) { alert('我是children') e.stopPropagation(); })
借此问题,复习了一下js事件,先看一下几个定义node
// IE之外的其余浏览器 // target :文档节点、document、window 或 XMLHttpRequest。 // type :字符串,事件名称,不含“on”,好比“click”、“mouseover”、“keydown”等。 // listener :实现了 EventListener 接口或者是 JavaScript 中的函数。 // useCapture :是否使用捕捉,通常用 false,事件触发时,会将一个 Event 对象传递给事件处理程序。 target.addEventListener(type,listener,useCapture);//添加 target.removeEventListener(type,listener,useCapture);//删除
// IE浏览器 // target :文档节点、document、window 或 XMLHttpRequest。 // type :字符串,事件名称,含“on”,好比“onclick”、“onmouseover”、“onkeydown”等。 // listener :实现了 EventListener 接口或者是 JavaScript 中的函数。 target.attachEvent(type, listener);//添加 target.detachEvent(type, listener);// 移除
兼容后的方法 var func = function(){}; //例:addEvent(window,"load",func) function addEvent(elem, type, fn) { if (elem.attachEvent) { elem.attachEvent('on' + type, fn); return; } if (elem.addEventListener) { elem.addEventListener(type, fn, false); } } //例:removeEvent(window,"load",func) function removeEvent(elem, type, fn) { if (elem.detachEvent) { elem.detachEvent('on' + type, fn); return; } if (elem.removeEventListener) { elem.removeEventListener(type, fn, false); } }
function eventHandler(e){ //获取事件对象 e = e || window.event;//IE和Chrome下是window.event FF下是e //获取事件源 var target = e.target || e.srcElement;//IE和Chrome下是srcElement FF下是target }
myTable.onclick = function () { e = e || window.event; var targetNode = e.target || e.srcElement; // 测试若是点击的是TR就触发 if (targetNode.nodeName.toLowerCase() === 'tr') { alert('You clicked a table row!'); } }
和事件的绑定实际上是相对应的,若是须要接触事件的绑定,运行对应的函数就能够了。若是是原生JS绑定则对应运行removeEventListener()和detachEvent()。浏览器
若是是jQuery的bind()和delegate()绑定,也是存在对应的解绑函数用以清除注册事件,好比unbind()和undelegate()。网络
看一个代码示例:app
var EventUtil = { //注册 addHandler: function(element, type, handler){ if (element.addEventListener){ element.addEventListener(type, handler, false); } else if (element.attachEvent){ element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, //移除注册 removeHandler: function(element, type, handler){ if (element.removeEventListener){ element.removeEventListener(type, handler, false); } else if (element.detachEvent){ element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } } };
几个概念dom
捕获阶段:事件对象经过目标的祖先从传播窗口到目标的父。这个阶段也被称为捕获阶段。异步
目标阶段:本次活动对象到达事件对象的事件的目标。这个阶段也被称为目标阶段。若是事件类型指示事件不起泡,则在完成此阶段后,事件对象将中止。函数
冒泡阶段:事件对象经过目标的祖先中传播以相反的顺序,开始与目标的父和与所述结束窗口。这个阶段也被称为冒泡阶段。
默认行为:事件一般由实现做为用户操做的结果分派,以响应任务的完成,或者在异步活动(例如网络请求)期间发信号通知进度。有些事件能够用来控制下一个实现可能采起的行为(或者撤销实现已经采起的行动)。这个类别中的事件被认为是可取消的,他们取消的行为被称为他们的默认行为。
取消事件:可取消的事件对象能够与一个或多个“默认动做”相关联。要取消事件,请调用该preventDefault()
方法。
一个图片
再上个小demo
<ul> <li>点我试试</li> </ul> <div id="s1" class="ss1">s1 <div id="s2" class="ss2">s2</div> </div>
var ul = document.getElementsByTagName('ul')[0]; var li = document.getElementsByTagName('li')[0];
element.addEventListener(event, function, useCapture) document.addEventListener('click',function(e){console.log('document clicked')},true);//第三个参数为true使用捕获,false为冒泡,false为默认 ul.addEventListener('click',function(e){console.log('ul clicked')},true); li.addEventListener('click',function(e){console.log('li clicked')},true); //IE低版本兼容写法 li.attachEvent('onclick',function(event){ debugger console.log('li clicked'); event.cancelBubble=true; }); s1.addEventListener('click',function () { console.log('s1 捕获方式') },true) s1.addEventListener('click',function () { console.log('s1 冒泡方式') },false) s2.addEventListener('click',function (e) { console.log('s2 捕获方式') // e.stopPropagation(); },true) s2.addEventListener('click',function () { console.log('s2 冒泡方式') },false)
点击li时,打印 依次为
1
|
ul clicked li clicked
|
点击s1时,打印依次为
s1 捕获方式 s1 冒泡方式
点击s2时,打印依次为
s1 捕获方式 s2 捕获方式 s2 冒泡方式 s1 冒泡方式
一、e.preventDefault()
var a = document.getElementById("testA"); a.onclick =function(e){ if(e.preventDefault){ e.preventDefault();// }else{ window.event.returnValue = false;//IE //注意:这个地方是没法用return false代替的 //return false只能取消元素 } }
二、return false javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡。
//原生js,只会阻止默认行为,不会中止冒泡 var a = document.getElementById("testA"); a.onclick = function(){ return false;//固然 也阻止了事件自己 }; //既然return false 和 e.preventDefault()都是同样的效果,那它们有区别吗?固然有。 //仅仅是在HTML事件属性 和 DOM0级事件处理方法中 才能经过返回 return false 的形式组织事件宿主的默认行为。
1 //jQuery,既阻止默认行为又中止冒泡 2 $("#testA").on('click',function(){ 3 return false;//固然 也阻止了事件自己 4 });
当须要中止冒泡行为时
function stopBubble(e) { //若是提供了事件对象,则这是一个非IE浏览器 if ( e && e.stopPropagation ){ e.stopPropagation(); //所以它支持W3C的stopPropagation()方法 }else{ window.event.cancelBubble = true; //不然,咱们须要使用IE的方式来取消事件冒泡 } }
当须要阻止默认事件时
function stopDefault( e ) { if ( e && e.preventDefault ){ e.preventDefault(); //阻止默认浏览器动做(W3C) }else { window.event.returnValue = false; //IE中阻止函数器默认动做的方式 } return false; }
让咱们回顾一下最初的问题,可能部分浏览器把事件的useCapture默认为true,致使点击子元素时父元素的事件先响应了,因而个人办法是在父元素的事件里进行判断
好比容器为
#a,
动态插入的元素为#b,
在#a上监听click事件,判断event.target.id是否是等于b便可,若是.b
class这种,以此类推。
咱们常常能遇到阻止冒泡,可是阻止捕获通常不会遇到,由于浏览器通常默认就给咱们阻止了,只能说什么状况都有啊,万事仍是得考虑周全。