没有其他说明、默认点击的是ds
事件的绑定
三种事件绑定的方法:
onTYPE = function(e){......}
优点:兼容性好。
缺点:过于古老,只能绑定一个函数,等同于写在DOM上的attribute。
# 第三个参数默认为false,代表冒泡、为true代表事件捕获。
eventTarget.addEventListener(TYPE,function,false)
优点:可以绑定多个函数,同一函数只能绑定一次。
缺点:IE9以下不支持。
elemnet.attachEvent(onTYPE,function)
优点:可以绑定多个函数,同一函数可以绑定多次。
缺点:仅限IE浏览器,并且在IE10以下。
什么是事件冒泡?
同一事件,子元素的事件触发后再触发父元素。(由内而外)。
事件的冒泡有什么好处?
想象一下现在我们有一个10列、100行的HTML表格,你希望在用户点击表格中的某一单元格的时候做点什么。比如说我有一次就需要让表格中的每一个单元格在被点击的时候变成可编辑状态。如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,并且有可能导致内存泄露甚至是浏览器的崩溃。相反地,使用事件代理的话,你只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。很大的节省了浏览器使用的内存。
冒泡demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div.clsg{width:500px;height: 500px;background: #FF9000;}
div.clsf{width:300px;height: 300px;
position: absolute;background: #FF4000;left: 520px;top:100px;}
div.clss{ position: absolute;left: 320px;top:100px;width: 100px;height: 100px;background: #0000ff;}
</style>
</head>
<body>
<div class="clsg">
<div class="clsf">
<div class="clss">
</div>
</div>
</div>
<script>
//冒泡
var dg=document.getElementsByClassName('clsg')[0];
var df=document.getElementsByClassName('clsf')[0];
var ds=document.getElementsByClassName('clss')[0];
document.addEventListener('click',function(){
console.log('document body click 冒泡');
},false);
dg.addEventListener('click',function(){
console.log('dg click 冒泡');
},false);
df.addEventListener('click',function(){
console.log('df click 冒泡');
},false);
ds.addEventListener('click',function(){
console.log('ds click 冒泡');
},false);
</script>
</body>
</html>
结果:
阻止冒泡
dg.addEventListener('click',function(){
console.log('dg click 冒泡');
},false);
df.addEventListener('click',function(){
console.log('df click 冒泡');
},false);
ds.addEventListener('click',function(e){
console.log('ds click 冒泡');
e = e || window.event; //兼容IE
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelable=true;//for IE
}
},false);
结果只有ds被触发
获取触发冒泡的目标
dg.addEventListener('click',function(e){
console.log('dg click 冒泡');
e = e || window.event;//IE
var target=e.target || e.srcElement;//IE
console.log(target);
},false);
//事件冒泡的来源;
df.addEventListener('click',function(e){
console.log('df click 冒泡');
},false);
ds.addEventListener('click',function(e){
console.log('ds click 冒泡');
// e = e || window.event; //兼容IE
// if(e.stopPropagation){
// e.stopPropagation();
// }else{
// e.cancelable=true;//for IE
// }
},false);
事件委托
什么是事件委托?
利用事件冒泡,在父节点上相应事件,而不是在子节点上影响事件。
优点:性能更高、灵活,不需要大量操作element、在绑定事件dom的子节点上可以进行动态的改而不需要充值事件、事件冒泡最大的好处就体现在了事件委托上。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>利用冒泡的事件委托</title>
<style>
ul >li{margin: 10px;width: 100px;height: 20px;cursor: pointer;background-color: red;padding: 10px;}
</style>
</head>
<body>
<!--ul#uid>li{$}*10-->
<ul id="uid">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script>
var ul=document.getElementById('uid');
ul.addEventListener('click',function(e){
e =e ||window.event;
var target =e.target || e.srcElement;
target.innerHTML=target.innerHTML+'click';
console.log(target.innerHTML);
console.log(target);
},false);
setTimeout(function(){
ul.innerHTML="";
},1500);
setTimeout(function(){
var li=document.createElement('li');
li.innerText="11";
ul.append(li);
},3000);
</script>
</body>
</html>
事件捕获
同一事件,先触发父元素,在触发子元素。(由外向内);
IE是没有事件捕获的、支持度最好的是chrome浏览器。
触发顺序:
首先捕获,然后是事件执行,最后是冒泡。不是所有事件都支持冒泡。
focus
,blur
,change
,submit
,reset
,select
这些事件不冒泡
捕获Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div.clsg{width:500px;height: 500px;background: #FF9000;}
div.clsf{width:300px;height: 300px;
position: absolute;background: #FF4000;left: 520px;top:100px;}
div.clss{ position: absolute;left: 320px;top:100px;width: 100px;height: 100px;background: #0000ff;}
</style>
</head>
<body>
<div class="clsg">
<div class="clsf">
<div class="clss">
</div>
</div>
</div>
<script>
var dg=document.getElementsByClassName('clsg')[0];
var df=document.getElementsByClassName('clsf')[0];
var ds=document.getElementsByClassName('clss')[0];
ds.addEventListener('click',function(e){
console.log('ds click 捕获');
},true);
df.addEventListener('click',function(e){
console.log('df click 捕获');
},true);
dg.addEventListener('click',function(e){
console.log('dg click 捕获');
},true);
</script>
</body>
</html>
执行结果
捕获的顺序查看
<script>
//冒泡
var dg=document.getElementsByClassName('clsg')[0];
var df=document.getElementsByClassName('clsf')[0];
var ds=document.getElementsByClassName('clss')[0];
document.addEventListener('click',function(){
console.log('document body click 冒泡');
},false);
dg.addEventListener('click',function(){
console.log('dg click 冒泡');
},false);
df.addEventListener('click',function(){
console.log('df click 冒泡');
},false);
ds.addEventListener('click',function(){
console.log('ds click 冒泡');
},false);
ds.addEventListener('click',function(e){
console.log('ds click 捕获');
},true);
df.addEventListener('click',function(e){
console.log('df click 捕获');
},true);
dg.addEventListener('click',function(e){
console.log('dg click 捕获');
},true);
</script>
查看结果
为什么是这样?
上文顺序已经提到,首先是捕获然后是事件执行,执行完了在冒泡。
捕获:是没有点你,然后你越俎代庖的提前执行。
冒泡:子节点执行完了、甩给你(父节点),然后继续向上执行。
ds哪里出现冒泡、原因是:既不是捕获也不是冒泡。ds是被点的本身,只不过执行内容写的是冒泡或捕获。这个地方只是事件执行。这个是由事件绑定的时间顺序决定的。
他和捕获和冒泡是没有关系的。
进行验证
<script>
//冒泡
var dg=document.getElementsByClassName('clsg')[0];
var df=document.getElementsByClassName('clsf')[0];
var ds=document.getElementsByClassName('clss')[0];
document.addEventListener('click',function(){
console.log('document body click 冒泡');
},false);
dg.addEventListener('click',function(){
console.log('dg click 冒泡');
},false);
df.addEventListener('click',function(){
console.log('df click 冒泡');
},false);
ds.addEventListener('click',function(e){
console.log('ds click 捕获');
},true);
ds.addEventListener('click',function(){
console.log('ds click 冒泡');
},false);
df.addEventListener('click',function(e){
console.log('df click 捕获');
},true);
dg.addEventListener('click',function(e){
console.log('dg click 捕获');
},true);
</script>