一. mouseenter和mouseleave何時被觸發
我們來看下官方解釋(mouseenter,mouseleave):
// onmouseenter:
Fires when the user moves the mouse pointer inside the boundaries of an object.
即:當鼠標移入元素對象的邊界之內時,激活該事件
// onmouseleave:
Fires when the user moves the mouse pointer outside the boundaries of the object.
即:當鼠標移出元素對象的邊界之外時,激活該事件
二. 與mouseover和mouseout的區別
官方站點在介紹mouseenter和mouseleave時,同時說明了與mouseover和mouseout的不同:
// onmouseenter vs onmouseover
Unlike the onmouseover event, the onmouseenter event does not bubble. In other words, the onmouseenter event does not fire when the user moves the mouse pointer over elements contained by the object, whereas onmouseover does fire.
即:onmouseenter不會冒泡,onmouseover則會,由於這個差異,當鼠標在元素邊界內移動時,不會激活onmouseenter(只在鼠標進入元素邊界內時激活),但會激活onmouseover(當該元素包含子元素時)。
// onmouseleave vs onmouseout
同上,由於存在冒泡的差異,導致了鼠標在元素邊界內移動時,會激活onmouseout(當該元素包含子元素時),但不會激活onmouseleave。
三. 為什么要模擬mouseenter和mouseleave?
原因很簡單:相對於mouseover和mouseout,mouseenter和mouseleave具有性能優勢(不會反復觸發),但只有IE支持它。。。
四. 如何模擬?
原理:監聽目標元素的mouseover和mouseout事件,只當鼠標移入目標元素時,才執行回調函數,忽略子元素上激活的mouseover和mouseout事件。我們通過事件對象的relatedTarget (ie瀏覽器為fromElement或toElement)屬性,來判斷鼠標是移入/移出目標元素,還是在目標元素內移動:
(1) 當mouseover被激活時,relatedTarget表示鼠標進入目標元素時,是從哪個元素離開的,我們可以對relatedTarget的值進行判斷:如果值不是目標元素,也不是目標元素的子元素,就說明鼠標已移入目標元素;
(2) 當mouseout被激活時,relatedTarget表示鼠標離開目標元素時,進入了哪個元素,我們同樣可以對relatedTarget的值進行判斷:如果值不是目標元素,也不是目標元素的子元素,就說明鼠標已移出目標元素;
五. 實例
// HTML:
<ul id="J_List">
<li><a href="#">item1</a></li>
<li><a href="#">item2</a></li>
<li><a href="#">item3</a></li>
</ul>
// JS(基於YUI):
<script type="text/javascript">
var Y = YAHOO.util,
Dom = Y.Dom,
Event = Y.Event;
// 獲取所有的li
var oList = Dom.get('J_List');
Event.on(oList, 'mouseover', function(e) {
var rt = Event.getRelatedTarget(e),
curElem = this;
// 如果rt不是curElem且不是curElem的子元素, 則就是mouse enter的情況
if (rt !== curElem && !Dom.isAncestor(curElem, rt)) {
console.log('enter: ' + curElem.id);
}
});
Event.on(oList, 'mouseout', function(e) {
var rt = Event.getRelatedTarget(e),
curElem = this;
// 如果rt不是curElem且不是curElem的子元素, 則就是mouse leave的情況
if (rt !== curElem && !Dom.isAncestor(curElem, rt)) {
console.log('leave: ' + curElem.id);
}
});
</script>