【学习笔记八】- JS 冒泡与捕获(事件流+事件处理程序+事件对象)

写在前面:

本人自学前端不久,博客的【学习笔记】既不算原创也不算转载,都是自己通过各个网站、博客、书籍、视频课程等学习的笔记,以及做的一些测试。



【事件流】


冒泡型事件:
例:div -> body -> html -> document
IE5.5及以前版本,会跳过<html>直接 body -> document
IE9、Firefox、Safari、Chrome将事件一直冒泡到 window

捕获型事件:与冒泡相反
IE9、Firefox、Safari、Chrome、Opera从window对象开始捕获

DOM事件流:
包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段,从document到document
IE9、Firefox、Safari、Chrome、Opera


【事件处理程序】


/*
HTML事件处理程序(响应某个事件的函数就叫做事件处理程序)

通过event变量可以直接访问事件对象
<input type="button" value="click me" onclick="alert(event.type)">
输出'click'

this指向事件的目标元素
<input type="button" value="click me" onclick="alert(this.value)">
输出'click me'

这样动态创建的函数扩展作用域,可以访问document及元素本身成员和访问表单元素的入口
function(){
  with(document){
    with(this.form){
      with(this){
        //元素属性值
      }
    }
  }
}
<form method="post">
<input type="text" name="username" value="">
<input type="button" value="Echo Username" onclick="alert(username.value)">
</form>
让事件处理程序无需引用表单元素就能访问其他表单字段

缺点:
1、如果用户在解析函数之前就触发事件,会引发错误,所以用try-catch块封装事件处理程序
<input type="button" value="click me" onclick="try{showMessage();}catch(ex){}">
2、这样扩展事件处理程序的作用域链在不同浏览器中会导致不同的结果,
不同js引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错
3、html和js代码紧密耦合

 */
/*
dom0级事件处理程序
没有兼容性问题

onlick 
事件冒泡阶段被处理

ele.onclick=function(){
	alert(this.id);
}
事件处理程序在其所属元素的作用域内运行,this引用当前元素ele

解绑时将其设为null,即ele.onclik = null;
 */
/*
dom2级事件处理程序
IE9+、Firefox、Safari、Chrome、Opera支持

addEventListener(event,handle,boolean)
removeEventListener(event, handle, boolean)
  boolean为true时捕获,为false时冒泡

可添加多个事件,按照添加顺序触发

解绑时参数和绑定时一样,用ele.removeEventListener(event, handle, boolean)
匿名函数无法移除

大多数情况下都是将事件添加到冒泡阶段方便兼容所有浏览器,
最好只在需要事件到达目标之前截获它时才将事件处理程序添加到捕获阶段。
 */
/*
ie事件处理程序
IE、Opera

attachEvent('on'+event, handle)
detachEvent("onclick", function(){})
IE8及以前版本,只支持冒泡

事件处理程序在全局作用域内运行,this指向window

可添加多个事件
添加的事件以相反的顺序触发
如果handle是同一个方法,绑定几次执行几次

解绑时参数和绑定时一样,用ele.detachEvent("onclick", function(){ });
匿名函数无法移除
 */
//跨浏览器的事件处理程序
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(element.detachEvent){
      element.detachEvent('on'+type,handler);
    }else{
      element['on'+type]=null;
    }
  }
};
var btn=document.getElementById('myBtn');
var handler=function(){
  alert('clicked');
};
EventUtil.addHandler(btn,'click',handler);
EventUtil.removeHandler(btn,'click',handler);



【事件对象】


//调用事件处理程序时,引擎会传入一个event对象到事件处理程序
//这个对象包含事件的状态和信息
//事件处理程序执行完event会被销毁
//DOM中的事件对象

//event对象的常用属性和方法:
//cancelable  Boolean   只读  表明是否可以取消事件的默认行为
//currentTarget Element   只读  其事件处理程序当前正在处理事件的那个元素
//eventPhase  Integer 只读  调用事件处理程序阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段
//target  Element   只读  事件的目标
//type  String  只读  被触发的事件的类型
//事件处理程序内部,对象this始终等于currentTarget的值,而target只包含事件的实际目标


//如果事件处理程序存在于按钮的父节点document.body中,button是事件click的实际目标,
//由于button上没有事件处理器,click事件就冒泡到了document.body处理
var btn=document.getElementById('myBtn');
var handler=function(event){
  switch(event.type){
    case "click":
      alert('clicked');
      break;
    case "mouseover":
      event.target.style.backgroundColor='red';
      break;
    case "mouseout":
      event.target.backgroundColor='';
      break;
  }
};
btn.onclick=handler;
btn.onmouseover=handler;
btn.onmouseout=handler;

//如果要阻止事件的默认行为(超链接打开页面、submit表单提交等)
//对于添加DOM0级事件处理器时,可以在事件处理器中return false
//对于添加DOM0/2级事件处理器时还可以用preventDefault()方法
//只有在cancelable为true时才可以用preventDefault()方法取消默认事件

var link=document.getElementById('myLink');
link.onclick=function(event){
  event.preventDefault(); 
}
link.addEventListener("click", function(event){
    var event = event || window.event;
    ...
    event.preventDefault(); 
},false);

//使用event.stopPropagation()方法阻止事件传播,
//无参数,可以同时取消冒泡和捕获,在捕获过程中使用后冒泡也不会发生

//直接添加到一个按钮的事件处理程序可以调用stopPropagation(),
//从而避免触发注册在document.body上面的事件处理程序

var btn=document.getElementById('myBtn');
btn.onclick=function(event){
  alert('clicked');
  event.stopPropagation();
};
document.body.onclick=function(event){
  alert("body clicked");
};

//事件对象的eventPhase属性可以用来确认当前正位于事件流的哪个阶段
var btn=document.getElementById('myBtn');
btn.onclick=function(event){
  alert(event.eventPhase);//2
};
document.body.addEventListener("click",function(event){
  alert(event.eventPhase);//1
},true);
document.body..onclick=function(event){
  alert(event.eventPhase);//3
};
//IE中的事件对象

//DOM0级添加事件处理器时,event作为window对象的属性
//用attachEvent()添加事件处理程序,有一个event对象作为参数被传入事件处理程序中,
//也可以通过window.event访问事件对象,
//如果是通过HTML特性指定的事件处理程序,还可以通过一个叫event的变量来访问事件对象
//<input type="button" value="click me" onclick="alert(event.type)">

//event对象的常用属性和方法:
//cancelBubble  Boolean   读/写   默认false,设为true可以取消事件冒泡(作用同DOM中的stopPropagation())
//returnValue   Boolean   读/写   默认true,设为false可以取消事件默认行为(作用同DOM中的preventDefault())
//srcElement    Element   只读    事件的目标(同dom中target)
//type          String    只读    被触发事件的类型
//因为事件处理程序的作用域是根据指定它的方式来确定的,
//所以不能认为this始终等于事件目标,最好使用event.srcElement

//将returnValue设为false,阻止默认行为
var link=document.getElementById('myLink');
link.onclick=function(){
  window.event.returnValue=false; 
}
link.attachEvent("onclick", function(e){
    var event = e || window.event;
    ...
    event.returnValue = false; 
},false);

//由于IE不支持捕获,所以只能阻止冒泡
var btn=document.getElementById('myBtn');
btn.onclick=function(event){
  alert('clicked');
  window.event.cancelBubble = true;
};
document.body.onclick=function(event){
  alert("body clicked");
};

//不是所有事件都能冒泡如:blur、focus、load、unload
//跨浏览器的事件对象
//由于IE不支持事件捕获,因此这个方法在跨浏览器情况下也只能用来阻止事件冒泡
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;
    }
  },

  getEvent:function(event){
    return event?event:window.event;
  },
  getTarget:function(event){
    return event.target||event.srcElement;
  },
  preventDefault:function(event){
    if(event.preventDefault){
      event.preventDefault();
    }else{
      event.returnValue=false;
    }
  },

  removeHandler:function(element,type,handler){
    if(element.removeEventListener){
      element.removeEventListener(type,handler,false);
    }else(element.detachEvent){
      element.detachEvent('on'+type,handler);
    }else{
      element['on'+type]=null;
    }
  },

  stopPropagation:function(event){
    if(event.stopPropagation){
      event.stopPropagation();
    }else{
      event.cancelBubble=true;
    }
  }

};

var btn=document.getElementById('myBtn');

btn.onclick=function(event){
  event=EventUtil.getEvent(event);
  //将这行代码添加到事件处理程序的开头,确保随时可以使用event对象;
  var target=EventUtil.getTarget(event);
  EventUtil.preventDefault(event);
}


var btn=document.getElementById('myBtn');

btn.onclick=function(event){
  alert("clicked");
  event=EventUtil.getEvent(event);
  EventUtil.stopPropagation(event);
}
document.body.onclick=function(event){
  alert("body clicked");
}


猜你喜欢

转载自blog.csdn.net/jiuto_crx/article/details/78025342