javascriptにおけるmouseoverとmouseoutイベントの最適化

3949 ワード

前に開発をした時にこの問題に出会いました.
あるコンテナにオンモスoverまたはonmouseoutイベントをバインドした場合、このコンテナに他の要素ノードがあると、マウスが内部を移動する時に、onmouseoverとonmouseoutイベントを頻繁にトリガします.これは実例があります.他の人のは参考にしてください.
 
私が欲しい効果は、イベントがマウスの中に入る時と離れる時だけです.マウスが元素範囲の中を移動する時はトリガしません.
 
なぜこの原因が現れますか?実は事件の泡が発生したためです.マウスを上に移動したり、コンテナの中のサブノードを移動したりすると、それぞれmouseoverとmouseoutイベントがトリガされ、domツリーに沿って上に泡が発生して、イベントハンドラ(モニター)によって捕獲されたり、ルートノード(documentまたはwindow)に泡ができたりするまで、つまりイベントは親レベルのオブジェクトに送られます.
 
問題の原因が分かりました.解決するのも簡単ですか?最初に考えたのは、イベントの泡をキャンセルし、event.ccerBbble=true(IE)とe.stopPropagation(他のブラウザ)を使っていましたが、簡単なテストの後、効果がないようです.(補足:私はテストで容器の中のaリンクノードを発泡解除しましたが、マウスが上に移動するとイベントが発生することが分かりました.Aノードの下にはspanノードがあります.容器の中のすべてのノードを泡にしないといけませんか?心ある人はテストできます.もし本当にこのようにすれば、それはとても気持ちが悪いです.N個のノードなら、泡を止めるべきですか?)
 
実はIEの下でマウスのイベントはmouse Enterとmouse Leaveがあります.これは移動と移動の際にトリガします.内部移動はトリガしません.残念なのはIEのみです.私たちが今やるべきことは、「非IEブラウザにモバイルEnterとmouse Leaveサポートを追加する」ということです.
 
jQueryはそうではありません.IEと他のすべてのブラウザでmouseoverとmouseoutイベントを直接修正しました.jQueryを参考にして、今のコードを全部もらいました.
まず、ノードオブジェクトが含まれているかどうかを判断する関数containsを紹介します.
/* p=parentNode, c=childNode */
function contains(p,c){  
    return p.contains ? 
           p != c && p.contains(c) :
           !!(p.compareDocumentPosition(c) & 16);  
}
ここで私たちはIEの下でfrom ElementとtoElementを使いました.この二つはIEの下でマウスを上に移動した時と移動した時のノードオブジェクトです.
/* e    ,target          */
function fixedMouse(e,target){  
        var related,
            type=e.type.toLowerCase();//        
        if(type=='mouseover'){
            related=e.relatedTarget||e.fromElement
        }else if(type='mouseout'){
            related=e.relatedTarget||e.toElement
        }else return true;
        return related && related.prefix!='xul' && !contains(target,related) && related!==target;
    }
それから私たちはどう使いますか?イベントをバインドする時、
//addListener          
addListener(target,'mouseover',function(e){
    e=e||window.event;
    if(fixedMouse(e, target)){
        //do something
    }
},false);
これは、ターゲットノードを移動する際にのみ、mouseoverとmouseoutをトリガすることになる.
もちろん、上のコードを単独でmouse Enterとmouse Leaveにパッケージ化してもいいです.これによって、mouseoverとmouseoutをもっと区別して呼び出すことができます.
具体的なデモについては、私が新しいテーマでオンラインする時に皆さんに見せてください.またはここのコメントの応答、参照ボタンの明示的な隠蔽を見て、上述のように用いられた.