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);
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章