深入理解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');