的onclick的事件處理函數(shù)了,那么就把cancelbubble設(shè)置為false即可。
二、 ie中拖動(dòng)dom元素的例子
/*
該函數(shù)由mousedown事件處理調(diào)用
它為隨后發(fā)生的mousemove和mouseup事件注冊了臨時(shí)的捕捉事件處理程序
并用這些事件處理程序拖動(dòng)指定的文檔元素
第二個(gè)參數(shù)必須是mousedown事件的事件對象
*/
function begindrag(elementtodrag,event)
{
//該元素當(dāng)前位于何處
//該元素的樣式性質(zhì)必須具有l(wèi)eft和top css屬性
//此外,我們假定他們用象素做單位
//var x=parseint(elementtodrag.style.left);
//var y=parseint(elementtodrag.style.top);
//計(jì)算一個(gè)點(diǎn)和鼠標(biāo)點(diǎn)擊之間的距離,下面的嵌套的movehandler函數(shù)需要這些值
var deltax=event.clientx-parseint(elementtodrag.style.left);
var deltay=event.clienty-parseint(elementtodrag.style.top);
// 注冊mousedown事件后發(fā)生的mousemove和mouseup事件的處理程序
// 注意,它們被注冊為文檔的捕捉事件處理程序
// 在鼠標(biāo)按鈕保持按下的狀態(tài)的時(shí)候,這些事件處理程序保持活動(dòng)的狀態(tài)
// 在按鈕被釋放的時(shí)候,它們被刪除
document.attachevent("onmousemove",movehandler);
document.attachevent("onmouseup",uphandler);
//我們已經(jīng)處理了該事件,不要讓別的元素看到它
event.cancelbubble=true;
event.returnvalue=false;
/*
這是在元素被拖動(dòng)時(shí)候捕捉mousemove事件的處理程序,它響應(yīng)移動(dòng)的元素
*/
function movehandler(e)
{
//把元素移動(dòng)到當(dāng)前的鼠標(biāo)位置
e=window.event;
elementtodrag.style.left=(event.clientx-deltax)+"px";
elementtodrag.style.top=(event.clienty-deltay)+"px";
//不要讓別的元素看到該事件
event.cancelbubble=true;
}
/*
該事件將捕捉拖動(dòng)結(jié)束的時(shí)候發(fā)生的mouseup事件
*/
function uphandler(e)
{
//注銷事件處理程序
document.detachevent("onmouseup",uphandler);
document.detachevent("onmousemove",movehandler);}
event.cancelbubble=true;
}
調(diào)用它的html文件代碼:
untitled page
拖動(dòng)我
this is a test.testing,testing
三、 dom中的高級事件處理
ie 6中的事件處理,并不是w3c dom標(biāo)準(zhǔn)的事件處理模型,所以如果上述代碼運(yùn)行在mozilla firefox的瀏覽器中,就會(huì)失去作用,同時(shí)即將發(fā)布的ie 7也將支持w3c dom的二級標(biāo)準(zhǔn),所以掌握dom的高級事件處理顯得就很重要了,因?yàn)閣3c dom二級標(biāo)準(zhǔn)是未來web的發(fā)展方向,同時(shí)w3c dom的api非常常用,為未來更加復(fù)雜的web開發(fā)提供了良好的基礎(chǔ)。
(一)事件處理程序的作用域和事件的傳播
在正式討論dom高級事件處理之前,我們有必要了解一下事件處理程序的作用域。事件處理程序的作用域要比普通的函數(shù)作用域復(fù)雜很多。普通的函數(shù)作用域鏈比較容易,例如在一個(gè)普通函數(shù)中查找一個(gè)變量a,那么javascript解釋器會(huì)先在該函數(shù)的調(diào)用對象中查找是否有a這個(gè)變量,如果沒有,將會(huì)在作用域鏈的下一個(gè)對象,一般是全局對象中查找。但是事件處理程序沒這么簡單,特別是用html的屬性定義的,它們的作用域鏈的頭部是調(diào)用它們的對象,而下一個(gè)對象并不是全局對象,而是觸發(fā)事件處理程序的對象。這樣就會(huì)出現(xiàn)一個(gè)問題,window和document都有一個(gè)方法open(),如果open()前面不加修飾,那么在事件處理的函數(shù)中將會(huì)調(diào)用document.open()方法,而不是常用的window.open()方法,所以使用的時(shí)候應(yīng)該明確指明是window.open()。
(二)事件傳播和注冊事件處理程序
1.事件傳播
在二級dom標(biāo)準(zhǔn)中,事件處理程序比較復(fù)雜,當(dāng)事件發(fā)生的時(shí)候,目標(biāo)節(jié)點(diǎn)的事件處理程序就會(huì)被觸發(fā)執(zhí)行,但是目標(biāo)節(jié)點(diǎn)的父節(jié)點(diǎn)也有機(jī)會(huì)來處理這個(gè)事件。事件的傳播分為三個(gè)階段,首先是捕捉階段,事件從document對象沿著dom樹向下傳播到目標(biāo)節(jié)點(diǎn),如果目標(biāo)的任何一個(gè)父節(jié)點(diǎn)注冊了捕捉事件的處理程序,那么事件在傳播的過程中就會(huì)首先運(yùn)行這個(gè)程序。下一個(gè)階段就是發(fā)生在目標(biāo)節(jié)點(diǎn)自身了,注冊在目標(biāo)節(jié)點(diǎn)上的相應(yīng)的事件處理程序就會(huì)執(zhí)行;最后是起泡階段,事件將從目標(biāo)節(jié)點(diǎn)向上傳回給父節(jié)點(diǎn),同樣,如果父節(jié)點(diǎn)有相應(yīng)的事件處理程序也會(huì)處理。在ie中,沒有捕捉的階段,但是有起泡的階段。可以用stoppropagation()方法來停止事件傳播,也就是讓其他元素對這個(gè)事件不可見,在ie 6中,就是把cancelbubble設(shè)置為true。
2.注冊事件處理程序
和ie一樣,dom標(biāo)準(zhǔn)也有自己的事件處理程序,不過dom二級標(biāo)準(zhǔn)的事件處理程序比ie的強(qiáng)大一些,事件處理程序的注冊用addeventlistner方法,該方法有三個(gè)參數(shù),第一個(gè)是事件類型,第二個(gè)是處理的函數(shù),第三個(gè)是一個(gè)布爾值,true表示制定的事件處理程序?qū)⒃谑录鞑サ碾A段用于捕捉事件,否則就不捕捉,當(dāng)事件發(fā)生在對象上才觸發(fā)執(zhí)行這個(gè)事件處理的函數(shù),或者發(fā)生在該對象的字節(jié)點(diǎn)上,并且向上起泡到這個(gè)對象上的時(shí)候,觸發(fā)執(zhí)行這個(gè)事件處理的函數(shù)。例如:document.addeventlistener("mousemove",movehandler,true);就是在mousemove事件發(fā)生的時(shí)候,調(diào)用movehandler函數(shù),并且可以捕捉事件。
可以用addeventlistener為一個(gè)事件注冊多個(gè)事件處理的程序,但是這些函數(shù)的執(zhí)行順序是不確定,并不像c#那樣按照注冊的順序執(zhí)行。
在mozilla firefox中用addeventlistener注冊一個(gè)事件處理程序的時(shí)候,this關(guān)鍵字就表示調(diào)用事件處理程序的文檔元素,但是其他瀏覽器并不一定是這樣,因?yàn)檫@不是dom標(biāo)準(zhǔn),正確的做法是用currenttarget屬性來引用調(diào)用事件處理程序的文檔元素。
3.二級dom標(biāo)準(zhǔn)中的event
和ie不同的是,w3c dom中的event對象并不是window全局對象下面的屬性,換句話說,event不是全局變量。通常在dom二級標(biāo)準(zhǔn)中,event作為發(fā)生事件的文檔對象的屬性。event含有兩個(gè)子接口,分別是uievent和mutationevent,這兩個(gè)子接口實(shí)現(xiàn)了event的所有方法和屬性,而mouseevent接口又是uievent的子接口,所以實(shí)現(xiàn)了uievent和event的所有方法和屬性。下面,我們就看看event、uievent和mouseevent的主要屬性和方法。
1.event
type:事件類型,和ie類似,但是沒有“on”前綴,例如單擊事件只是“click”。
target:發(fā)生事件的節(jié)點(diǎn)。
currenttarget:發(fā)生當(dāng)前正在處理的事件的節(jié)點(diǎn),可能是target屬性所指向的節(jié)點(diǎn),也可能由于捕捉或者起泡,指向target所指節(jié)點(diǎn)的父節(jié)點(diǎn)。
eventphase:指定了事件傳播的階段。是一個(gè)數(shù)字。
timestamp:事件發(fā)生的時(shí)間。
bubbles:指明該事件是否起泡。
cancelable:指明該事件是否可以用preventdefault()方法來取消默認(rèn)的動(dòng)作。
preventdefault()方法:取消事件的默認(rèn)動(dòng)作;
stoppropagation()方法:停止事件傳播。
2.uievent
view:發(fā)生事件的window對象。
detail:提供事件的額外信息,對于單擊事件、mousedown和mouseup事件都代表的是點(diǎn)擊次數(shù)。
3.mouseevent
button:一個(gè)數(shù)字,指明在mousedown、mouseup和單擊事件中,鼠標(biāo)鍵的狀態(tài),和ie中的button屬性類似,但是數(shù)字代表的意義不一樣,0代表左鍵,1代表中間鍵,2代表右鍵。
altkey、ctrlkey、shiftkey、metakey:和ie相同,但是ie沒有最后一個(gè)。
clientx、clienty:和ie的含義相同,但是在dom標(biāo)準(zhǔn)中,這兩個(gè)屬性值都不考慮文檔的滾動(dòng)情況,也就是說,無論文檔滾動(dòng)到哪里,只要事件發(fā)生在窗口左上角,clientx和clienty都是0,所以在ie中,要想得到事件發(fā)生的坐標(biāo)相對于文檔開頭的位置,要加上document.body.scrollleft和document.body.scrolltop。
screenx、screeny:鼠標(biāo)指針相對于顯示器左上角的位置,如果你想打開新的窗口,這兩個(gè)屬性很重要。
relatedtarget:和ie中的fromelement、toelement類似,除了對于mouseover和mouseout有意義外,其他的事件沒什么意義。
(三)兼容于兩種主流瀏覽器的拖動(dòng)dom元素的例子
好了,剛才講了這么多dom編程和ie中的事件,那么如何編寫兼容ie和mozilla firefox兩種主流瀏覽器的拖拽程序呢?代碼如下:
function begindrag(elementtodrag,event)
{
var deltax=event.clientx-parseint(elementtodrag.style.left);
var deltay=event.clienty-parseint(elementtodrag.style.top);
//hgx注:個(gè)人覺得使用通過css的left/top屬性來計(jì)算不是一個(gè)好方法,可以通過offserleft和offsertop得到。if(document.addeventlistener)
{
document.addeventlistener("mousemove",movehandler,true);
document.addeventlistener("mouseup",uphandler,true);
}
else if(document.attachevent)
{
document.attachevent("onmousemove",movehandler);
document.attachevent("onmouseup",uphandler);
}
if(event.stoppropagation) event.stoppropagation();
else event.cancelbubble=true;
if(event.preventdefault) event.preventdefault();
else event.returnvalue=false;
function movehandler(e)
{
if (!e) e=window.event; //如果是ie的事件對象,那么就用window.event
//全局屬性,否則就用dom二級標(biāo)準(zhǔn)的event對象。
//hgx注:也可以這樣:e = e || window.event;
elementtodrag.style.left=(event.clientx-deltax)+"px";
elementtodrag.style.top=(event.clienty-deltay)+"px";
if(event.stoppropagation) event.stoppropagation();
else event.cancelbubble=true;
}
function uphandler(
e)
{
if(document.removeeventlistener)
{
document.removeeventlistener("mouseup",uphandler,true);
document.removeeventlistener("mousemove",movehandler,true);}
else
{
document.detachevent("onmouseup",uphandler);
document.detachevent("onmousemove",movehandler);}
}
if(event.stoppropagation) event.stoppropagation();
else event.cancelbubble=true;
}
該文章在 2010/4/24 11:24:04 編輯過