DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> JS中mouseover和mouseout多次觸發問題如何解決
JS中mouseover和mouseout多次觸發問題如何解決
編輯:關於JavaScript     

問題描述

我希望當鼠標移動到id1上的時候,id2顯示,當鼠標離開id1的時候,id2顯示。問題如下:

1.當鼠標從id1上移動到id2上的時候,id由有顯示變為不顯示,然後變為顯示

2.當鼠標從id2上移動到id1上的時候, id2有顯示變為不顯示,然後變為顯示

我希望的是當鼠標在id1或者id2上移動的時候,id2一直顯示,不發生變化。

<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div id="id1" style="width:800px; height:400px; background-color:#F23">
<div id="id2" style="width:400px; height:300px; background-color:#0F8; display:none;">
</div>
</div>
<script type="text/javascript">
$("#id1").mouseover(function(){
$(this).children().fadeIn(1000);
}).mouseout(function(){
$(this).children().fadeOut(1000);
});
</script>

這裡寫圖片描述

問題解決辦法

最開始的問題分析,當鼠標從id1上移動到id2上的時候,由於鼠標由id2離開進入id1,針對id1觸發了一個mouseout事件,於是id2有顯示變為不顯示,接著在鼠標移動到id2上,在id2上觸發了一個mouseover事件,由於冒泡機制,id2上的mouseover冒泡到id1之前,觸發了id1上的mouseover事件,然後id2由不顯示變為顯示。同理,當鼠標從id2上移動到id1上的時候,針對id2,觸發了一個mouseout事件,還是因為冒泡機制,mouseout事件傳到id1上,id2由顯示變為不顯示,接著鼠標移動到id1之前,觸發了一個mouseover事件,然後id2有不顯示變為顯示。

看來,上面的問題歸根要解決的是,當鼠標由id1上移動到id2上的時候,阻止id1的mouseout事件;當鼠標從id2上移動到id1上的時候,阻止id2的mouseout事件冒泡到id1之上。那麼僅僅通過阻止冒泡是解決不了問題。

為了解決這樣的問題,jQuery提供了mouseenter和mouseleave方法。於是將JS代碼改為如下,很好解決了問題。

$("#id1").mouseenter(function(){
$(this).children().fadeIn(1000);
}).mouseleave(function(){
$(this).children().fadeOut(1000);
});

很多地方都有介紹mouseenter、mouseleave與mouseover、mouseout,於是復制粘貼了一個。

/*********************************************************/

1.mouseover與mouseenter

不論鼠標指針穿過被選元素或其子元素,都會觸發 mouseover 事件。

只有在鼠標指針穿過被選元素時,才會觸發 mouseenter 事件。

2.mouseout與mouseleave

不論鼠標指針離開被選元素還是任何子元素,都會觸發 mouseout 事件。
只有在鼠標指針離開被選元素時,才會觸發 mouseleave 事件。

/*********************************************************/

現象確實是這個現象,但是過程說的有點模糊,我的理解如下:

當鼠標指針移動到被選元素,會觸發 mouseover 事件,這個大家都知道,當鼠標指針由被選元素移動到其子元素,先是觸發被選元素的mouseout事件,然後子元素的mouseover事件冒泡到被選元素,此時相當於被選元素先執行了一個mouseout事件,然後執行了一個mouseover事件。

為了驗證將代碼改為如下

<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div id="id1" style="width:800px; height:400px; background-color:#F23">
<div id="id2" style="width:400px; height:300px; background-color:#0F8; position:absolute; top:300px;">
</div>
</div>
<script type="text/javascript">
$("#id1").mouseover(function(){
//$(this).children().fadeIn(1000);
console.log('a');
}).mouseout(function(){
//$(this).children().fadeOut(1000);
console.log('b');
});
</script>

鼠標從頁面移動到id1,然後由id1移動到id2上,控制台輸出如下圖

這裡寫圖片描述 

可以看出id1先後調用了mouseover、mouseout、mouseover事件,正好和上面分析的相同。

mouseenter與mouseleave實現分析

原理分析

從上面分析,我們可以看出,要實現mouseenter與mouseleave的效果,就是當鼠標從被選元素移動到其子元素上的時候,被選元素不執行mouseout事件,也不執行子類冒泡過來的mouseover事件,當鼠標從被選元素子元素移動到被選元素上的時候,被選元素不執行mouseover事件,也不執行子類冒泡過來的mouseout事件。

要實現上面的效果,我們需要event對象的一個屬性relatedTarget,這個屬性就是用來判斷 mouseover和mouseout事件目標節點的相關節點的屬性。簡單的來說就是當觸發mouseover事件時,relatedTarget屬性代表的就是鼠標剛剛離開的那個節點,當觸發mouseout事件時它代表的是鼠標移向的那個對象。由於MSIE不支持這個屬性,不過它有代替的屬性,分別是 fromElement和toElement。除此,我們還需要contains方法,來判斷一個對象是否包含在另外一個對象中。

這樣當鼠標移動,需要判斷以下兩條即可

1.調用mouseover,只需要判斷relatedTarget是否被選元素的子元素,如果是,則不執行(當於從被選元素子元素移動到被選元素,不執行mouseover;當於從被選元素移動到被選元素子元素,不執行冒泡過來的mouseover);

2.調用mouseout,只需要判斷relatedTarget是否被選元素的子元素,如果是,則不執行(當於從被選元素子元素移動到被選元素,不執行子元素冒泡過來的mouseout;當於從被選元素移動到被選元素子元素,不執行mouseover);

實現過程

判斷兩個元素是否存在包含關系

jquery中封裝了contains函數如下

這裡寫圖片描述 

可以簡化為如下

//判斷兩個a中是否包含b
function contains(a,b){
return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
}

compareDocumentPosition介紹

這個方法是 DOM Level 3 specification 的一部分,允許你確定 2 個 DOM Node 之間的相互位置。這個方法比 .contains() 強大。這個方法的一個可能應用是排序 DOM Node 成一個詳細精確的順序。NodeA.compareDocumentPosition(NodeB)返回的信息描述如下:

比特 序號 意義

通過上面我們就可以理解為什麼要寫成a.compareDocumentPosition(b) & 16因為如果節點 A 包含節點 B,就會返回16,16&16=1,其他的情況結果都會0。

獲取兼容性性的relatedTarget

為了兼容各種浏覽器,參考jquery源碼,寫出如下代碼,來獲取mouseover和mouseout事件目標節點的相關節點的屬性relatedTarget。

function getRelated(e){
var related;
var type=e.type.toLowerCase();//這裡獲取事件名字
if(type=='mouseover'){
related=e.relatedTarget||e.fromElement
}else if(type='mouseout'){
related=e.relatedTarget||e.toElement
}
return related; 
}

改進mouseover和mouseout

改進mouseover和mouseout以實現改進mouseenter與mouseleave效果,所有代碼如下。

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="id1" style="width:800px; height:400px; background-color:#F23">
<div id="id2" style="width:400px; height:300px; background-color:#0F8; position:absolute; top:300px;">
</div>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script type="text/javascript">
//判斷兩個a中是否包含b
function contains(a,b){
return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
}
function getRelated(e){
var related;
var type=e.type.toLowerCase();//這裡獲取事件名字
if(type=='mouseover'){
related=e.relatedTarget||e.fromElement
}else if(type='mouseout'){
related=e.relatedTarget||e.toElement
}
return related; 
}
$(function(){
$("#id1").mouseover(function(e){
//判斷鼠標從哪移到id1上面
var related=getRelated(e); 
//如果related是id1的子元素id2,即從子元素id2移動到id1,或是related為id1,即從id1移動到其子元素id2上面,則不進行任何操作,否則進行相應的操作
if(this!=related && !contains(this,related)){
console.log('mouseover');
}
}).mouseout(function(e){
//判斷鼠標要從id1上面移動到哪去?
var related=getRelated(e); 
//如果related是id1,即當id1從其子元素移動到id1上,或是related是id2,即從id1上移動到其子元素,不進行任何操作,否則進行相應的操作
if(this !=related && !contains(this,related)){
console.log('mouseout');
}
});
});
</script>
</body>
</html>

測試,鼠標移動路線如下圖路線

由控制台可以很看出,此刻的mouseover和mouseout已經完全具備mouseenter與mouseleave效果效果。

這裡寫圖片描述 

代碼的封裝

如果每次進行這樣的操作,都需要加載Jquery或是寫很多代表,將是件繁瑣的事,為了便於以後操作,進行了適當的封裝,模擬Jquery,生成自己的mouseenter與mouseleave。代碼封裝到dqMouse.js文件中,如下:

(function(w){
var dqMouse = function(obj) {
// 函數體
return new dqMouse.fn.init(obj);
}
dqMouse.fn = dqMouse.prototype = {
// 擴展原型對象
obj:null,
dqMouse: "1.0.0",
init: function(obj) {
this.obj=obj;
return this;
},
contains:function(a,b) {
return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
},
getRelated:function(e) {
var related;
var type=e.type.toLowerCase();//這裡獲取事件名字
if(type=='mouseover'){
related=e.relatedTarget||e.fromElement
}else if(type='mouseout'){
related=e.relatedTarget||e.toElement
}
return related; 
},
over:function(fn){
var obj=this.obj;
var _self=this;
obj.onmouseover=function(e){ 
var related=_self.getRelated(e); 
if(this!=related && !_self.contains(this,related)){
fn();
}
}
return _self;
},
out:function(fn){
var obj=this.obj;
var _self=this;
obj.onmouseout=function(e){
var related=_self.getRelated(e); 
if(obj!=related && !_self.contains(obj,related)){
fn();
}
}
return _self;
}
} 
dqMouse.fn.init.prototype = dqMouse.fn;
window.dqMouse = window.$$= dqMouse;
})(window);

調用的源文件如下:

<div id="id1" style="width:800px; height:400px; background-color:#F23">
<div id="id2" style="width:400px; height:300px; background-color:#0F8; position:absolute; top:300px;">
</div>
</div>
<script type="text/javascript" src="dqMouse.js"></script>
<script type="text/javascript">
var id1=document.getElementById('id1');
$$(id1).over(function(){
console.log('mouseover');
}).out(function(){
console.log('mouseout');
}); 
</script>

以上所述是小編給大家介紹的JS中mouseover和mouseout多次觸發問題如何解決的相關內容,希望對大家有所幫助!

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved