1. 程式人生 > >深入理解DOM事件機制系列第六篇——事件模擬

深入理解DOM事件機制系列第六篇——事件模擬

前面的話

  事件是網頁中某個特別的瞬間,經常由使用者操作或通過其他瀏覽器功能來觸發。但實際上,也可以使用javascript在任意時刻來觸發特定的事件,而此時的事件就如同瀏覽器建立的事件一樣。本文將詳細介紹事件模擬

引入

  以下面的實際需求為例,來詳細說明事件模擬的使用。按鈕一的點選效果是彈出1。而我們通過新增按鈕二來模擬按鈕一的效果

複製程式碼
<button id="btn1">按鈕一</button>
<script>
btn1.onclick = function(){
    alert(1);
}
</script>
複製程式碼

事件複製

  通過呼叫相同的事件處理函式,來完成相同的功能

複製程式碼
<button id="btn1">按鈕一</button>
<button id="btn2">按鈕二</button>
<script>
btn1.onclick=function(){
    alert(1);
}
btn2.onclick = btn1.onclick;
</script>
複製程式碼

  但是,有一個問題,在不知道按鈕一的事件處理函式以及以何種呼叫形式呼叫時,這種方法是危險的

  下面這種情況將無法正確模擬

複製程式碼
<button id="btn1"
>按鈕一</button> <button id="btn2">按鈕二</button> <script> if(btn1.addEventListener){ btn1.addEventListener('click',function(){alert(1);}) }else{ btn1.attachEvent('onclick',function(){alert(1);}) } btn2.onclick = btn1.onclick; </script>
複製程式碼

click()方法

  使用click()方法,則無論使用何種事件處理程式都可以實現模擬效果

複製程式碼
<button id="btn1">按鈕一</button>
<button id="btn2">按鈕二</button>
<script>
if(btn1.addEventListener){
    btn1.addEventListener('click',function(){alert(1);})
}else{
    btn1.attachEvent('onclick',function(){alert(1);})
}
btn2.onclick = function(){
    btn1.click();
}
</script>
複製程式碼

  雖然click()方法可以完美模擬click事件,但是對於其他事件並沒有相應的模擬方法,就需要用到下面要介紹的事件模擬了。好吧,我承認這個引入比較長。但是,我不知道如何再縮短了 

模擬機制

  事件模擬包括3個部分:建立事件、初始化以及觸發事件。某些情況下,初始化與建立事件一起進行。最終,通過dispatchEvent()方法或fireEvent()方法來觸發事件

  對於不同的事件型別,有不同的建立方法。下面以mouseover事件為例

MouseEvent()

  使用MouseEvent()方法可以建立滑鼠事件。實際上,MouseEvent()方法在建立事件的同時,也包括了初始化的操作

  [注意]IE瀏覽器和safari瀏覽器不支援

  最後使用dispatchEvent()方法在當前節點上觸發指定事件。該方法返回一個布林值,只要有一個監聽函式呼叫了Event.preventDefault(),則返回值為false,否則為true

  [注意]IE8-瀏覽器不支援

複製程式碼
function simulateMouseOver(obj) {
  var event = new MouseEvent('mouseover', {
    'bubbles': true,
    'cancelable': true
  });
  obj.dispatchEvent(event);
}
複製程式碼 複製程式碼
<button id="btn1">按鈕一</button>
<button id="btn2">按鈕二</button>
<script>
if(btn1.addEventListener){
    btn1.addEventListener('mouseover',function(){alert(1);})
}else{
    btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
  var event = new MouseEvent('mouseover', {
    'bubbles': true,
    'cancelable': true
  });
  obj.dispatchEvent(event);
}
btn2.onmouseover = function(){
    simulateMouseOver(btn1);
}
</script>
複製程式碼

creatEvent()

  在document物件上使用createEvent()方法可以用來建立event物件。這個方法接收一個引數,表示要建立的事件型別的字串

  [注意]IE8-瀏覽器不支援createEvent()方法

  在使用document.createElement建立事件之後,還需要使用與事件有關的資訊對其進行初始化,每種不同型別的事件都有不同的初始化方法

複製程式碼
事件型別                事件初始化方法
UIEvents               event.initUIEvent
MouseEvents            event.initMouseEvent
MutationEvents         event.initMutationEvent
HTMLEvents             event.initEvent
Event                  event.initEvent
CustomEvent            event.initCustomEvent
KeyboardEvent          event.initKeyEvent
複製程式碼

  下面是initMouseEvent()方法的引數,它們與滑鼠事件的event物件所包含的屬性一一對應。其中,前4個引數對正確地激發事件至關重要,因為瀏覽器要用到這些引數;而剩下的所有引數只有在事件處理程式中才會用到

  [注意]IE8-瀏覽器不支援initMouseEvent()方法

  type(字串):表示要觸發的事件型別,例如"click"

  bubbles(布林值):表示事件是否應該冒泡。為精確地模擬滑鼠事件,應該把這個引數設定為true

  cancelable(布林值):表示事件是否可以取消。為精確地模擬滑鼠事件,應該把這個引數設定為crue

  view(AbstractView):與事件關聯的檢視。這個引數幾乎總是要設定為document.defaultView

  detail(整數):與事件有關的詳細資訊。這個值一般只有事件處理程式使用,但通常都設定為0

  screenx(整數):事件相對於螢幕的X座標

  screenY(整數):事件相對於螢幕的Y座標

  clientX(整數):事件相對於視口的X座標

  clientY(整數):事件相對於視口的Y座標

  ctrlKey(布林值):表示是否按下Ctrl鍵。預設值為false

  altkey(布林值):表示是否按下了Alt鍵。預設值為false

  shiftKey(布林值):表示是否按下了Shift鍵。預設值為false

  metaKey(布林值):表示是否按下了Meta鍵。預設值為false

  button(整數):表示按下了哪一個滑鼠鍵。預設值為0

  relatedTarget(物件):表示與事件相關的物件。這個引數只在模擬mouseover或mouseout時使用

【寫法一】createEvent()方法使用MouseEvents引數

複製程式碼
function simulateMouseOver(obj) {
    var event = document.createEvent('MouseEvents');
    event.initMouseEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);        
     obj.dispatchEvent(event);
}    
複製程式碼 複製程式碼
<button id="btn1">按鈕一</button>
<button id="btn2">按鈕二</button>
<script>
if(btn1.addEventListener){
    btn1.addEventListener('mouseover',function(){alert(1);})
}else{
    btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
    var event = document.createEvent('MouseEvents');
    event.initMouseEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);    
     obj.dispatchEvent(event);
}
btn2.onmouseover = function(){
    simulateMouseOver(btn1);
}
</script>
複製程式碼

【寫法二】createEvent()方法使用Event引數

複製程式碼
function simulateMouseOver(obj) {
    var event = document.createEvent('Event');
    event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);        
     obj.dispatchEvent(event);
}    
複製程式碼 複製程式碼
<button id="btn1">按鈕一</button>
<button id="btn2">按鈕二</button>
<script>
if(btn1.addEventListener){
    btn1.addEventListener('mouseover',function(){alert(1);})
}else{
    btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
    var event = document.createEvent('Event');
    event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);        
     obj.dispatchEvent(event);
}    
btn2.onmouseover = function(){
    simulateMouseOver(btn1);
}
</script>
複製程式碼

createEventObject()

  在IE10-瀏覽器中可以使用document.createEventObject()方法建立event物件。這個方法不接受引數,結果會返回一個通用的event物件

  IE瀏覽器不支援初始化事件,需要手動為這個物件新增所有必要的資訊

  IE8-瀏覽器不支援dispatchEvent()事件。在IE8-瀏覽器中觸發事件需要呼叫fireEvent()方法,這個方法接受兩個引數:事件處理程式的名稱和event物件。在呼叫fireEvent()方法時,會自動為event物件新增srcElement和type屬性

複製程式碼
function simulateMouseOver(obj) {
    var event = document.createEventObject();
    event.bubbles = true;
    event.cancelable = true;
     obj.fireEvent('onmouseover',event);
}    
複製程式碼

相容

  下面使用document.createEvent()方法和createEventObject()來實現相容 

複製程式碼
function simulateMouseOver(obj) {
    var event;
    if(document.createEvent){
        event = document.createEvent('Event');
        event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);        
         obj.dispatchEvent(event);    
    }else{
        event = document.createEventObject();
        event.bubbles = true;
        event.cancelable = true;
         obj.fireEvent('onmouseover',event);
    }
}    
複製程式碼 複製程式碼
<button id="btn1">按鈕一</button>
<button id="btn2">按鈕二</button>
<script>
if(btn1.addEventListener){
    btn1.addEventListener('mouseover',function(){alert(1);})
}else{
    btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
    var event;
    if(document.createEvent){
        event = document.createEvent('Event');