Javascript事件详解

想要清楚的对javascript的事件有一个详细的了解,我们必须搞明白以下几件事情:

首先,必须明白以下几个概念
什么是事件? 什么是事件处理程序? 事件类型有哪些?事件流?事件冒泡?事件捕获?事件对象? 常见浏览器兼容问题怎么解决?

事件的概念
javas使我们有能力创建动态页面,事件是可以被浏览器侦测到的行为,比方说,我们可以在用户点击某一个按钮的时候产生一个onclick来触发某个函数,常见的事件有click,load,unload等

事件处理程序
响应某个事件的函数则称为事件处理程序,或者叫做事件侦听器。
click、mousemove、load等都是事件的名称,事件处理程序就是在事件的前面加上“on”,click事件的事件处理程序为onclick。

事件类型

1.鼠标事件
- click:单击
- dbclick:双击
- mousedown:当用户鼠标还未弹起触发
- mouseup:当用户释放按钮时触发
- mouseover:当鼠标移到某个元素上方时触发
- mouseout:当离开元素上方时触发
- mousemove:当鼠标指针元素时触发

2.键盘事件
- keydown:当用户按键盘上任意键触发
- keypress:当用户按键盘上的字符键触发
- keyup:当用户释放键盘上的键触发

3.HTML事件
- load:当整个页面加载完成
- unload:当页面完全卸载后在window上面触发,或在框架集卸载后在框架集上触发
- select:当用户选择文本框(input/textarea)中的一个或多个字符事触发
- change:当文本框(input/textarea)内容且焦点后触发
- focus:当页面或元素焦点后在window及相关元素上触发
- blur:当页面或元素失去焦点时在window及相关元素上触发
- submit:当用户点击提交按钮时在form上触发
- reset:当用户点击重置按钮时在form上触发
- resize:当窗口或框架的大小发生变化时在window或框架上触发
- scroll:当用户滚动带滚动条的元素时触发

4.滚轮事件:mousewheel(IE6+均支持)、DOMMouseScroll(Firefox支持的,与mousewheel效果一样)。是使用鼠标滚轮时触发的。

事件流
事件流描述的是从页面中接收事件的顺序,对于事件流,IE与NetScape提出了完全相反的顺序,IE提出的是事件冒泡流,即事件开始的时候由最具体的接收,逐级向上传播较为不具体节点;网提出的时间捕获流,即事件由最不具体的开始接收,然后逐级向下传播到最具体的节点


window.onload= function(){ 
  document.onclick=function(){
    alert('document');
  } 
  document.documentElement.onclick = function(){    //documentElement 属性可返回文档的根节点。
    alert('html');
  }
  document.body.onclick=function  () {
    alert('body');
  }
  document.getElementById('box').onclick= function(){
    alert('div');
  }
  document.getElementsByTagName('input')[0].onclick= function(evt){
    alert('input');
    //var e=evt||window.event;
    //e.stopPropagation();  //W3C取消事件冒泡
    //e.cancleBubble=true;    //IE取消事件冒泡  
    //alert(typeof  e.stopPropagation);
    stop(evt);
  } 
}
//兼容(取消事件冒泡)
function stop(evt){
   var e=evt||window.event;
   if (typeof e.stopPropagation=='function') {
    e.stopPropagation();
   }else{
    e.cancleBubble=true;
   }

}

事件对象
在触发DOM上的某个事件的时候,会产生一个事件对象event,而在这个对象中包含着所有与事件有关的信息,其中有两个信息是我们最常用,分别是type和target,type表示的被触发事件的类型,target表示的是事件的目标

//支持的DOM的浏览器可以直接获取event;IE通过window.event获取
document.onclick = function(evt){
 //var e=event||window.event;   //跨浏览器获取event 
 // alert(e.type) //click
    alert(getTarget(evt));  
}

//跨浏览器获取event目标 
function getTarget(evt){
  var e = event||window.event;
  return e.target||e.srcElement;
}

事件绑定
1.传统事件绑定(包括内联模型和脚本模型)
脚本模型

//问题一:会覆盖
window.onload = function(){
  alert('li');  //被覆盖了
}
window.onload=function(){
  alert('lii');    //前者被覆盖了 打印出lii
}

----------

解决覆盖问题
//alert(typeof window.onload);  //一开始没有注册window.onload  那么就是null
window.onload = function(){
  alert('li');  //被覆盖了
}
if (typeof window.onload=='function') { //判断是否存在上一个事件
  var saved=null;   
  saved = window.onload;    //保存上一个事件对象
};
//alert(typeof window.onload);  //如果已经有window.onload 那么返回的就是一个函数 所以可以进行判断
window.onload=function(){
  if(saved)saved();    //执行上一个事件window.onload=function(){};
  alert('meiling');  //执行本事件
}

2.现代事件绑定(DOM2级模型)


//W3C自带的两个添加事件和删除事件
//1.解决覆盖问题 
window.addEventListener('load',function(){
  alert('lee');
},false)  //lee

window.addEventListener('load',function(){
  alert('le');  //le
},false)
//解决相同函数屏蔽的问题
window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
window.addEventListener('load',init,false);
function init(){
  alert('lee');     //只会弹出一个lee
} 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="script.js"></script>
    <style type="text/css">
      .red{
        width: 100px;
        height: 100px;
        background-color: red;
      }

      .blue{
        width: 200px;
        height: 200px;
        background-color: blue;
      }
    </style>
</head>
<body>
    <div id="box" class="red">测试</div>
</body>
</html>
//3.是否可以传递this(可以传递)
//js部分
window.addEventListener('load',function(){
  var box = document.getElementById('box');
  box.addEventListener('click',toBlue,false);
},false);

function toRed(){
  this.className='red';
  this.removeEventListener('click',toRed,false)
  this.addEventListener('click',toBlue,false);  
}
function toBlue(){
  this.className='blue';
  this.removeEventListener('click',toBlue,false)
  this.addEventListener('click',toRed,false);
}  
//4.添加一个额外的方法会不会被覆盖,或者只能执行一次
window.addEventListener('load',function(){
  var box = document.getElementById('box');
  box.addEventListener('click',function(){
    alert('lee');
  },false);
  box.addEventListener('click',toBlue,false);
},false);

function toRed(){
  this.className='red';
  this.removeEventListener('click',toRed,false)
  this.addEventListener('click',toBlue,false);  
}
function toBlue(){
  this.className='blue';
  this.removeEventListener('click',toBlue,false)
  this.addEventListener('click',toRed,false);
}   

IE事件处理函数

//IE事件处理函数 attachEvent() detachEvent()
//ie不支持捕获,只支持冒泡, ie添加事件不能屏蔽重复的函数, ie中的this指向的是window而不是DOM对象
//1.覆盖问题 ,解决了 但有不同 ,顺序不同 倒过来的     
window.attachEvent('onload',function(){
  alert('leee');
})
window.attachEvent('onload',function(){
  alert('lee');
})
window.attachEvent('onload',function(){
  alert('le');
})

//2.相同函数屏蔽的问题  未解决 无法屏蔽
window.attachEvent('onload',init);
window.attachEvent('onload',init);
function init(){
  alert('lee');   //弹出两个lee
}

//3.是否可以传递this
window.attachEvent('onload',function(){
  var box = document.getElementById('box');
  box.attachEvent('onclick',function(){
    // alert(this===box);  //false
    alert(this===window);  //不能传递this   true
  })
})

// 4.添加一个额外的方法会不会被覆盖,或者只能执行一次   解决了
 window.attachEvent('onload',function(){
  var box = document.getElementById('box');
  box.attachEvent('onclick',function(){
   alert('lee');
  });
  box.attachEvent('onclick',function(){
   alert('le');
  });
})

IE和w3c兼容事件切换器

//跨浏览器添加事件
function addEvent(obj,type,fn){
  if (obj.addEventListener) {
    obj.addEventListener(type,fn,false);
  }else if (obj.attachEvent) {
    obj.attachEvent('on'+type,fn);
  }
}

//跨浏览器移除事件
function removeEvent(obj,type,fn){
  if(obj.removeEventListener){
    obj.removeEventListener(type,fn,false);
  }else if(obj.detachEvent){
    obj.detachEvent('on'+type,fn);
  }
}

//跨浏览器获取目标对象
function getTarget(evt){
  if (evt.target) {    //w3c
    return evt.target;
  }else if(window.event.srcElement){  //IE
    return window.event.srcElement;
  }
}

addEvent(window,'load',function(){
  var box  = document.getElementById('box');
  addEvent(box,'click',toBlue);
})

function toRed(evt){
  var that = getTarget(evt); 
  that.className='red';
  removeEvent(that,'click',toRed);
  addEvent(that,'click',toBlue);
}
function toBlue(evt){
  var that = getTarget(evt);
  that.className='blue';
  removeEvent(that,'click',toBlue);
  addEvent(that,'click',toRed);
} 

其它

//跨浏览器添加事件
function addEvent(obj,type,fn){
  if (obj.addEventListener) {
    obj.addEventListener(type,fn,false);
  }else if (obj.attachEvent) {
    obj.attachEvent('on'+type,fn);
  }
}

//跨浏览器移除事件
function removeEvent(obj,type,fn){
  if(obj.removeEventListener){
    obj.removeEventListener(type,fn,false);
  }else if(obj.detachEvent){
    obj.detachEvent('on'+type,fn);
  }
}

//兼容 阻止默认行为
function preDef(evt){
  var e =evt||window.event;
  if (e.preventDefault) {

    e.preventDefault();
  }else {
    e.returnValue = false;
  }
}
//上下文菜单事件:contextmenu(很常用) ,当我们右击网页的时候会出现windows自带的菜单
//那么我们可以使用contextmenu事件来修改我们指定的菜单,但前提是把右击的默认行为取消掉
addEvent(window,'load',function(){
  var text =  document.getElementById('text');
  addEvent(text,'contextmenu',function(evt){
    preDef(evt);
    var menu = document.getElementById('menu');
    var e =evt||window.event;
    menu.style.left=e.clientX+'px';   //得到鼠标的座标  
    menu.style.top=e.clientY+'px';
    menu.style.display='block';

    addEvent(document,'click',function(){
      menu.style.display='none';
    })
  })
})
//卸载前事件beforeunload,这个事件可以在帮助离开本页时给出相应的提示,‘离开’或‘返回’操作
addEvent(window,'beforeunload',function(evt){
  preDef(evt);
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章