JavaScript、浏览器、事件之间的关系
JavaScript程序采用了异步事件驱动编程(Event-driven programming)模型,事件驱动程序模型基本的实现原理基本上都是使用 事件循环(Event Loop),这部分内容涉及浏览器事件模型、回调原理。在javascript中使用了异步事件,也就是说:js中的事件都是异步执行的.1、事件绑定的方法
- 行内绑定 直接在DOM元素上通过设置
on + eventType绑定事件处理程序。例如:
<a href="#none" onclick="alert('clicked')">点击我</a>- 在DOM元素上重写事件回调函数
使用DOM Element上面的on + eventType属性 API
var el = getElementById('button'); //button是一个<button>元素
el.onclick = function(){ alert('button clicked.') };
el.onclick = function(){ alert('Button Clicked.') };
//实际之弹出'Button Clicked.',函数发生了覆盖- 标准绑定方法
标准的绑定方法有两种,addEventListener和attachEvent前者是标准浏览器支持的API,后者是IE8以下浏览器支持的API:
<button class="left" id="left">left</button>
var ele = document.getElementById('left');
if(ele.addEventListener){
ele.addEventListener('click',function(){
alert(this.id);
},false);
}
if(ele.attachEvent){
ele.attachEvent('onclick',function(){
alert('1');
})
}
需要注意的是:
1. addEventLister的第一个参数事件类型是不加on前缀的,而attachEvent中需要加on前缀。
2. addEventLister中的事件回调函数中的this指向事件元素target本身,而attachEvent中的事件回调函数的this指向的是window。
3. addEventLister有第三个参数,true表示事件工作在捕获阶段,false为冒泡阶段(默认值:false)。而attachEvent只能工作在冒泡阶段。
在chrome中运行如下代码:
<a href="javascript:alert('1')" onclick="alert('2')" id="link">link</a>
<script
var link = document.getElementById('link');
link.onclick = function(){
alert('3');
};
link.addEventListener('click',function(){
alert('4');
});
link.addEventListener('click',function(){
alert('5');
});
</script>点击后弹出顺序是: 3 -> 4 -> 5 -> 1
这里第4行代码覆盖了行内的onclick定义,如果注释了这一行,输入顺序为: 2 -> 4 -> 5 -> 1,而addEventListener之间不会发生覆盖。
2、解除事件绑定
对于上述的前二个方法,解除事件绑定只需要将对应的事件函数设为null,就可以了:
var el = document.getElementById('button');
el.onclick = null;对于上述第三种方法使用removeListen()方法即可,在IE8中,对应使用detachEvent()。注意,他们和上面的注册方法一一对应,不能混用。
var ele = doucment.getElementById('button');
var handler = function(){alert('button')};
if(ele.addEventListener){
ele.addEventListener('click',handler,false);
}
if(ele.attachEvent){
ele.attachEvent('onclick',handler);
}
//移除事件
if(ele.removeEventListener){
ele.removeEventListener('click',handler,false);
}
if(ele.detachEvent){
ele.detachEvent('onclick',handler);
}
3、事件的冒泡与捕获
冒泡:在一个元素上触发的某一事件,会在这个元素的父辈元素上会依次由内向外触发该事件,直到window元素。
捕获:在一个元素上触发的某一事件,这个元素的每一层的所有子元素上触发该事件,并逐层向内,直到所有元素不再有子元素。
事件间回到函数参数是一个事件对象,它里面包括许多事件属性和方法,比如,我们可以用以下方式阻止冒泡和默认事件:
function handler(event){
event = event || window.event;
//阻止冒泡
if(event.stopPropagation){
event.stopPropagation(); //标准
}else{
event.cancelBubble = true; //IE
}
//阻止默认事件
if(event.preventDefault) {
event.preventDefault();
}else{
event.returnValue = false;
}
}
普通注册事件只能阻止默认事件,不能阻止冒泡
element = document.getElementById('submit');
element.onclick = function(e){
return false; //通过返回false,阻止冒泡
}
4、事件代理
- 事件委托注册方法,不论内容有多少都只注册1次,支持动态添加元素:
<ul id="list">
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
</ul>
<script>
var list = document.getElementById('list');
var handler = function(event){
event = event || window.event;
target = event.target || event.srcElement;
if(target.nodeName && target.nodeName === 'Li'){
console.log(target.innerHTML);
}
}
if(list.addEventListener){
list.addEventListener('click',handler,false);
}else{
list.attachEvent('onclick',handler);
}
//添加元素
var nodeList = document.createElement('li');
nodeList.innerHTML = 'item-6';
list.appendChild(nodeList);
</script>5、事件封装
//冒泡事件模型
var myEventUtil = {
//添加事件函数
addEvent: function(ele, type, func){
if(ele.addEventlistener){
ele.addEventlistener(type,func,false);
}else if(ele.attachevent){
ele.attachevent('on' + type,func);
}else{
ele["on" + type] = func;
}
},
//删除事件
delEvent: function(ele, type, func){
if(ele.removeEventListener){
ele.removeEventListener(type, func, false);
}else if(ele.detachEvent){
ele.detachEvent('on' + type, func);
}else{
ele["on" + type] = null;
}
},
//获取触发事件的源DOM元素
getSrcElement: function(event){
return event.target || event.srcElement;
},
//获取事件类型
getType: function(event) {
return event.type;
},
//获取事件
getEvent: function(event) {
return event || window.event;
}
//阻止事件冒泡
stopPropagation: function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
//禁用默认行为
preventDefault: function(event) {
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
}
}