簡單的鼠標移動事件:
進入
mouseenter:不冒泡
mouseover: 冒泡
不論鼠標指針穿過被選元素或其子元素,都會觸發 mouseover 事件
只有在鼠標指針穿過被選元素時,才會觸發 mouseenter 事件
移出
mouseleave: 不冒泡
mouseout:冒泡
不論鼠標指針離開被選元素還是任何子元素,都會觸發 mouseout 事件
只有在鼠標指針離開被選元素時,才會觸發 mouseleave 事件
我們通過一個案例觀察下問題:
給一個嵌套的層級綁定mouseout事件,會發現mouseout事件與想象的不一樣
我們發現一個問題mouseout事件:
- 無法阻止冒泡
- 在內部的子元素上也會觸發
同樣的問題還有mouseover事件,那么在stopPropagation方法失效的情況下我們要如何停止冒泡呢?
- 為了阻止mouseover和mouseout的反復觸發,這里要用到event對象的一個屬性relatedTarget,這個屬性就是用來判斷 mouseover和mouseout事件目標節點的相關節點的屬性。簡單的來說就是當觸發mouseover事件時,relatedTarget屬性代表的就是鼠標剛剛離開的那個節點,當觸發mouseout事件時它代表的是鼠標移向的那個對象。由於MSIE不支持這個屬性,不過它有代替的屬性,分別是 fromElement和toElement。
- 有了這個屬性,我們就能夠清楚的知道我們的鼠標是從哪個對象移過來,又是要移動到哪里去了。這樣我們就能夠通過判斷這個相關聯的對象是否在我們要觸發事件的對象的內部,或者是不是就是這個對象本身。通過這個判斷我們就能夠合理的選擇是否真的要觸發事件。
- 這里我們還用到了一個用於檢查一個對象是否包含在另外一個對象中的方法,contains方法。MSIE和FireFox分別提供了檢查的方法,這里封裝了一個函數。
jQuery的處理也是如出一轍
jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout", pointerenter: "pointerover", pointerleave: "pointerout" }, function(orig, fix) { jQuery.event.special[orig] = { delegateType: fix, bindType: fix, handle: function(event) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if (!related || (related !== target && !jQuery.contains(target, related))) { event.type = handleObj.origType; ret = handleObj.handler.apply(this, arguments); event.type = fix; } return ret; } }; });