在IE的全系列中都實現了mouseenter和mouseleave事件,但是在早期的w3c瀏覽器中卻沒有實現這兩個事件。有時候,我們需要使用
mouseenter事件來防止子元素的冒泡,這就涉及到事件兼容性的問題了。
先比較mouseenter和mouseover的異同點,當從元素外圍進入元素內部時同時觸發mouseover和mouseenter事件,但是在元素內部,
鼠標進入元素子節點時會繼續觸發mouseover事件,該事件是可以向上冒泡的;對於mouseenter則不會冒泡,當然也不會觸發該事件。
mouseleave亦然。
用mouseover來模擬mouseenter的關鍵在於利用事件的relatedTarget判定鼠標是否在元素內部移動,這也涉及到dom元素contain()
的實現。為了高效的實現contain方法,盡量使用瀏覽器的原生API,如果沒有則只能向上回溯。
function contain(p,c){ if(p == c)return false; if(p.compareDocumentPosition){ return !!(p.compareDocumentPosition(c) & 16); }else if(p.contains){ return p.contains(c); } var cur; while(c = c.parentNode){ if(c.nodeType == 3 || c.nodeType == 8) continue; if(c !== p) continue; else{ return true; } } return false; }
然后着重修復mouseover事件:
var fixMouseenter = function(el,fn){ return window.VBArray ? { el: el, type: 'mouseenter', fn: fn } : { el: el, type: 'mouseover', fn: function(e){ !contain(el,e.relatedTarget) && fn.call(this,arguments); } }; }; var fixMouseleave = function(el,fn){ return window.VBArray ? { el: el, type: 'mouseleave', fn: fn } : { el: el, type: 'mouseout', fn: function(e){ !contain(el,e.relatedTarget) && fn.call(this,arguments); } }; };
這樣對於非IE瀏覽器都進行事件修復,但是缺點也有不少,就是新版本的w3c瀏覽器都已經實現了這兩個事件,所以我們就沒有必要
在進行事件修復。
