阻止事件传播
阻止事件传播e.stopPropagation()
谷歌浏览器
阻止事件传播(冒泡阶段)
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small');
oBig.addEventListener('click',function(){//事件处理函数
console.log('big 冒泡阶段我被点击了');
},false);//false事件冒泡阶段触发
oSmall.addEventListener('click',function(){//事件处理函数
console.log('small 被点击了');
},false);//false事件冒泡阶段触发
点击small的盒子打印的结果
点击small触发small的事件处理函数,然后big的事件处理函数也被触发了,因为事件冒泡机制才触发了big的事件处理函数
因为事件冒泡机制才触发了big
的事件处理函数,那么该怎么阻止small
事件冒泡??? (冒泡阶段)
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small');
oBig.addEventListener('click',function(){
console.log('big 冒泡阶段我被点击了');
},false);
oSmall.addEventListener('click',function(e){
e.stopPropagation();//阻止事件传播
console.log('small 被点击了');
},false);
这样写上e.stopPropagation()
着句代码small的点击事件就不会往上冒泡了,自然而然就不会被big所捕捉到,那么就不会触发big的事件处理函数了
点击small的打印结果
阻止事件传播(捕获阶段)
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small');
oBig.addEventListener('click',function(){
console.log('big 捕获阶段我被点击了');
},true);
oSmall.addEventListener('click',function(e){
e.stopPropagation();
console.log('small 被点击了');
},true);
点击small的盒子打印的结果
点击small,首先事件监听器的第3个参数写的是true,true是在事件捕获阶段触发事件处理函数
点击small是从上到下捕获的(document—>html—>body–>big—>small),那么点击small肯定会触发big的事件处理函数。
因为true是事件捕获阶段,所以他会从上到下看,先看big有没有对应的事件处理函数有就会触发,然后因为点击了small的事件处理函数
那么该怎么阻止事件捕获阶段??? (捕获阶段)
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small');
oBig.addEventListener('click',function(e){
e.stopPropagation(); //阻止事件传播
console.log('big 捕获阶段我被点击了');
},true);
oSmall.addEventListener('click',function(){
console.log('small 被点击了');
},true);
捕获阶段:捕获到document(没有对应的事件处理函数)---->捕获到html(没有对应的事件处理函数)- -->捕获到body(没有对应的事件处理函数)- - ->捕获到big(有对应的事件处理函数)加上e.stopPropagation()
阻止事件传播代码就不会触发small的事件处理函数了- - ->捕获到small(有对应的事件处理函数)不会被big传播了
点击small的打印结果
阻止事件传播e.cancelBubble = true
IE低版本
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small');
oBig.attachEvent('onclick',function(){
console.log('big 捕获阶段我被点击了');
},true);
oSmall.attachEvent('onclick',function(e){
e.cancelBubble = true;//IE低版本阻止事件传播
console.log('small 被点击了');
},true);
点击small的打印结果
在IE低版本e.cancelBubble = true
可以阻止事件传播
封装stopBubble(e)
兼容函数
function stopBubble(e){
if(e.stopPropagation){ //谷歌
e.stopPropagation()
}else{ //IE低版本
e.cancelBubble = true
}
}
阻止默认事件
什么是网页的默认事件???: 右键出菜单、图片拖动、a标签跳转、表单提交这些网页的默认事件
阻止默认事件 e.preventDefault()
谷歌 (IE8以上)
那该怎么阻止右键出菜单的默认事件呢??
document.oncontextmenu = function(e){
console.log('huashneg');
e.preventDefault();//取消默认事件
};
鼠标右键点击了5从huasheng,没有出菜单
那该怎么阻止a标签的默认跳转事件
点击a标签,a标签会跳转到另一个页面,这是a标签的默认行为
var oA = document.getElementsByTagName('a')[0];
//获取a标签元素
oA.onclick = function(e){//个a标签正个点击事件任何在取消默认事件
e.preventDefault();//取消默认事件
};
return false
也能阻止默认事件
在DOM
0级事件中,也能阻止掉默认事件
document.oncontextmenu = function(e){
console.log('huashneg');
return false;
}
阻止默认事件:掉鼠标右键默认菜单
鼠标右键点击了4会
也能取消a标签的默认事件
var oA = document.getElementsByTagName('a')[0];
oA.onclick = function(){
return false;//取消a标签的默认事件
};
那可以DOM
2级事件中,能阻止默认事件吗??
var oA = document.getElementsByTagName('a');
document.addEventListener('contextmenu',function(){
return false;
},false);
答案是不能的:在DOM2级事件中不能通过,return false
阻止默认事件
阻止默认事件e.returnValue = false
IE低版本(IE8一下)
document.oncontextmenu = function(e){
console.log('huashneg');
e.returnValue = false;//取消IE及其以下的默认事件
}
e.returnValue = false
IE低版本(IE8一下)的可以阻止默认事件
封装cancelHandler
兼容性函数
//这个函数的作用是阻止浏览器默认行为 并且兼容不同的浏览器
function cancelHandler(e){
if(e.preventDefault){ //谷歌
e.preventDefault()
}else{ //IE低版本
e.returnValue = false
}
}
事件源对象
事件源对象 --> 指向触发事件源头的节点
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small')
oBig.addEventListener('click',function(){
console.log('oBig');
},false);
oSmall.addEventListener('click',function(){
console.log('oSmall');
},false);
点了oSmall
打印了两个,那么怎么知道到底你是点击了那个呢??
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small')
oBig.addEventListener('click',function(e){
console.log(e.target);//e.target是指事件的源头(节点)
},false);
oSmall.addEventListener('click',function(){
},false);
点击small然后这个点击事件会冒泡到big上面,然后big上面的事件处理函数就会触发,那么现在的事件对象的target属性,就是用来指向这您初始用户点了谁,到底是那个节点引起了这个事件或者说是那个节点触发了这个事件。
是small这个节点触发了这个事件,因为点击了这个节点事件冒泡到big上面的事件处理函数一个属性能记录到底是触发了谁才使得我这个事件处理函数被触发了。
例子:
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small')
document.body.addEventListener('click',function(e){
console.log(e.target);
},false)
oBig.addEventListener('click',function(e){
console.log(e.target);
},false);
oSmall.addEventListener('click',function(e){
console.log(e.target);
},false);
点击small
你是点击了small,因为事件冒泡的机制big会捕获的,事件在往上冒document.body也会捕获的,然后这个源头到底是谁,是small(他获取的是一个DOM节点)
点击big
你是点击了big,因为事件冒泡的机制docume.body会捕获的,然后会往上冒找到html看看html有没有对应的事件处理函数(有就会触发没有就不会)
点击document.body
你点击了document.body,冒泡机制往上找有没有对应的事件和事件处理函数,一看html和document没有对应的事件和事件处理函数就不会触发
event.target
IE8以上高本版浏览器
那么IE8以下的底版版浏览器怎么找到源对象
var oBig = document.getElementById('big');
var oSmall = document.getElementById('small')
oBig.addEventListener('click',function(e){
console.log(e.srcElement);
},false);
oSmall.addEventListener('click',function(e){
console.log(e.srcElement);
},false);
e.target
谷歌 和 e.srcElement
IE低版本 找到事件源对象,获取的是元素的DOM,有相对应的事件处理函数的DOM就会触发谁,没有就不会触发
兼容事件源对象的,兼容写法
var oBig = document.getElementById('big');
oBig.addEventListener('click',function(e){
var target = e.target || e.srcElement;//兼容写法
console.log(target)
},false);
事件委托
那怎么点击对应的文字,出对应的索引呢??
var aLi = document.getElementsByTagName('li');//获取li元素
for(var i=0;i<aLi.length;i++){
//遍历每个li的length
aLi[i].onclick = function(){
console.log(i);
};
};
那为什么点击一次li打印一次5呢??
因为for
循环是同步代码,点击事件里面的回调函数执行是异步代码,那么先执行同步代码在执行异步代码,等同步代码执行完是i=5
,然后在执行点击事件里面的回调函数(异步代码),那么每点击一个li就会打印一次5
那么怎么让每次点击之后打印对应的索引呢??
只所以打印出来5,点击了第一个li,会触发回调函数里面的i,那么这个回调函数执行的时候AO中是没有i的,那我会从GO中里找,GO中的i=5
那我会从GO中拿到i=5,那么每次点击li就会打印出来5
这时我们需要延长这个点击事件的函数作用域链,让这个点击事件的外部还有一个作用域
var aLi = document.getElementsByTagName('li');//获取li元素
for(var i=0;i<aLi.length;i++){***加粗样式***
//遍历每个li的length
(function(i){//延长作用域链//AO:i=0
aLi[i].onclick = function(){
console.log(i);//我没有i我会去父级AO中找是i=0
};
})(i);
};
从作用域链的角度来说,当前的点击事件里面的回调函数中的所处的环境是上面这个函数的环境
那么我们不用这种形式也能打印出来对应的索引
var aLi = document.getElementsByTagName('li');//获取li元素
//遍历每个li的length
for(var i=0;i<aLi.length;i++){
//aLi[i]是一个节点,是节点我们就可以给他自定义一个属性
aLi[i].index = i;//给aLi[i]设置自定义属性index
aLi[i].onclick = function(){
console.log(this.index);
};//每次打印就查询this里面的index属性
//this指向自身
};
这样写是有一个弊端:现在是给5个li的上面onclick属性都赋值了一个函数,也就是在内存中开辟了5个空间存放了5个函数,然后把第一个函数给了aLi[i].onclick
属性以此类推
通过for循环的形式,给5个li中的每一个li都绑定了一个函数,这种形式在内存中开辟了5个空间,然后函数作为引用值是在内存占据空间的。
那么我们怎么避免这种占据大量空间那该怎么写??
可以使用事件委托的形式
那什么是事件委托呢??
利用事件冒泡的原理把子级的事件委托给祖先元素
var oUl = document.getElementsByTagName('ul')[0];//获取ul元素
oUl.onclick = function(e){
console.log(e.target.innerText-1);
};//innerText打印对应的文本
通过事件冒泡这种机制,能够触发父元素的事件处理函数,同样的通过事件源对象我有能够早到自己(子元素),在父元素的事件处理函数中操纵自己,把这个事件委托给父元素。
那么添加新的子元素时怎么做事件委托
var oUl = document.getElementsByTagName('ul')[0];//获取Ul元素
var aLi = document.getElementsByTagName('li');//获取li元素
for(var i=0;i<aLi.length;i++){
aLi[i].index = i;
aLi[i].onclick = function(){
console.log(this.index);
};
};
var oLi = document.createElement('li');//创建节点
oUl.appendChild(oLi);//添加节点
oLi.innerText = '6';//给节点添加内容
为什么新加的li没有打印???
因为你在for循环只给5个li绑定了对应的事件和对应的事件处理函数,然后后面新增的li元素没有绑定对应的事件,对应新增的li是没有的。
用事件委托的方式
var oUl = document.getElementsByTagName('ul')[0];//获取Ul元素
var oLi = document.createElement('li');//创建节点
oUl.appendChild(oLi);//添加节点
oLi.innerText = '6';//给节点添加内容
oUl.onclick = function(e){
console.log(e.target.innerText-1);
};//通过事件委托的方式
当你新增节点的时候不用绑定对应的事件,事件委托自动的给你绑定上,他可以在内存中开辟一个空间存储着子元素的所有要绑定的事件处理函数。
优点
- 不需要循环绑定每个子元素,可以节约浏览器性能
- 添加新的子元素时,不需要再给新元素绑定事件
拖拽图片
/*
* 拖拽使用的三个事件
* onmousedown
* onmousemove
* onmouseup
* */
var oImg = document.getElementsByTagName('img')[0];
oImg.onmousedown = function(e){
e = e||winodw.event; //兼容事件对象
var startX = e.clientX; //记录鼠标按下时的水平位置
var startY = e.clientY; //记录鼠标按下时的竖直位置
var startLeft = this.offsetLeft; //记录鼠标按下时的图片的初始水平位置
var startTop = this.offsetTop; //记录鼠标按下时的图片的初始竖直位置
document.onmousemove = function(e){
e = e||winodw.event; //兼容事件对象
var moveX = e.clientX; //记录鼠标移动时的水平位置
var moveY = e.clientY; //记录鼠标移动时的竖直位置
oImg.style.left = startLeft + moveX - startX +'px';
oImg.style.top = startTop + moveY - startY +'px';
}
oImg.onmouseup = function(){
document.onmousemove = null;//解除onmousemove的事件处理函数
}
return false;//阻止浏览器的默认行为
}