標籤:
本文並沒有像標題說的那樣,真正阻止事件元素的子項目冒泡...
只是在子項目冒泡到事件元素處時進行了一個判斷,判斷是否要觸發事件,哦...不對 應該是是否要運行事件函數中的相關操作...
首先你可以猛戳這裡: 問題的出現
註:jquery中的mouseover/out事件也有此問題
解決方案一:
在ie下有mouseenter 與 mouseleave事件來替代mouseover 和 mouseout。
網上很多說法,這兩個事件只有ie支援,其他瀏覽器不支援。
但是我在最新版本的Firefox與Google都支援了mouseenter 與 mouseleave!!!!!
另外ie是的支援範圍是:[ie5+ ,所以我們還是別噴ie了...
其他瀏覽器測試了下:
在Firefox/3.6.28是不支援mouseenter 與 mouseleave的,Firefox具體從哪個版本開始支援這兩個事件,就不得而知了...
在Opera9.50 Alpha 與Opera9.00 Beta都不支援。其實Opera現在完全可以不要測試了,最新版的Opera都是webkit核心...
Google低版本未測試...
當然這些老版本瀏覽器基本可以不用管了,所以這應該是最好的解決辦法了:用mouseenter 與 mouseleave事件來替代mouseover 和 mouseout。
此二事件的執行個體戳這:mouseenter與mouseleave
註:jquery中也有mouseenter 與 mouseleave事件,相容所有瀏覽器。
解決方案二:
上面那個方法在老版本的Firefox與Google是不支援的,如果你希望得到最大範圍的相容,那可以繼續往下看
我們利用var reltg = e.relatedTarget ? e.relatedTarget : e.type == ‘mouseout‘ ? e.toElement : e.fromElement 來擷取事件相關元素。再通過這個事件相關元素它跟事件元素的關係(包含的關係),來判斷是否做相關事件處理。
對於mouseout事件來說,reltg就是滑鼠指標離開目標時,滑鼠指標進入的節點。
對於mouseover 事件來說,reltg就是滑鼠指標移到目標節點上時所離開的那個節點。
在li的mouseout的事件函數中,如果reltg為li的子項目我們就不要運行相關操作,如果reltg為li的父元素就運行相關操作。
我們可以通過下面的isMouseLeaveOrEnter函數來判斷li與reltg的內含項目關聯性:
//判斷事件相關元素與li的關係 如果事件相關元素為li的子項目就返回false 反之返回truefunction isMouseLeaveOrEnter(e, handler) { if (e.type != ‘mouseout‘ && e.type != ‘mouseover‘) return false; var reltg = e.relatedTarget ? e.relatedTarget : e.type == ‘mouseout‘ ? e.toElement : e.fromElement; while (reltg && reltg != handler) reltg = reltg.parentNode; return (reltg != handler);};Li.onmouseout = function(e) { e = e||window.event; if (isMouseLeaveOrEnter(e,this)) { //運行相關操作 };}
來看看效果:戳我
此方法明顯的缺點就是isMouseLeaveOrEnter中要遍曆所有的父元素了,效能問題
解決方案三:
此方法與方法二其實思路是一樣的,只是我們這裡通過compareDocumentPosition/contains來判斷li與reltg的內含項目關聯性,最佳化了方法二遍曆所有父元素帶來的效能問題。
直接看代碼吧:
//判斷node是否為parent的子項目//if node == parent 也會返回truefunction contains(parent, node) { if(parent.compareDocumentPosition){ //ff var _flag = parent.compareDocumentPosition(node); return (_flag == 20 || _flag == 0)? true : false; }else if(parent.contains){ //ie return parent.contains(node); }};Li.onmouseout = function(e) { e = e||window.event; var relatedEle = e.relatedTarget ? e.relatedTarget : e.type == ‘mouseout‘ ? e.toElement : e.fromElement if (!contains(this, relatedEle)) { show.innerHTML=show.innerHTML+‘0‘; }}
看效果:戳我
compareDocumentPosition() 方法比較兩個節點,並返回描述它們在文檔中位置的整數。
傳回值可能是:
1:沒有關係,兩個節點不屬於同一個文檔。
2:第一節點(P1)位於第二個節點後(P2)。
4:第一節點(P1)定位在第二節點(P2)前。
8:第一節點(P1)位於第二節點內(P2)。
16:第二節點(P2)位於第一節點內(P1)。
32:沒有關係,或是兩個節點是同一元素的兩個屬性。
注釋:傳回值可以是值的組合。例如,返回 20 意味著在 p2 在 p1 內部(16),並且 p1 在 p2 之前(4)。
而[ie8- 不支援compareDocumentPosition()方法,需要用contains代替compareDocumentPosition()方法那麼強大,它是用來確定 nodeB 是否包含在另一個 nodeA 中:nodeA .contains( nodeB )
javascript阻止子項目冒泡觸發父元素的mouseover、mouseout