89360


## 要約

jQueryとjQueryUIを用いて，マウスオーバーすると色が変わり，マウスアウトすると元に戻るアニメをつけようとしていたところ，`.stop()`の付け方によっては無限の繰り返しが発生してしまうことがわかりました．しかし，考えても原因がわかりません．

マウスを動かしていないのにmouseoverイベントが繰り返し発生しているようなのですが，それはおかしなことだと思います．

## これまでに試したこと

  * ブラウザはChromeとedgeで試してみましたが，結果は変わりませんでした．

  * 読み込むjQueryのバージョンを変えてみましたが，結果は変わりませんでした．

## コード

CDNを使って，HTMLファイル単体で再現できるようにしてみました．

下記HTMLファイルをテキストエディタに貼り付け，ブラウザで開いてください．

マウスオーバーして，マウスをそのままにすると無限ループが発生することがあります．

[code]

    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>無限ループするanimate</title>
        <style>
            #buttons2 button p:first-child {
                position: absolute;
            }
            #buttons2 button p:nth-child(2) {
                opacity: 0;
            }
        </style>
        <script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
    </head>
    <body>
    
    <div id="buttons2">
        <button>
            <p>hogehoge</p>
            <p>mokemoke</p>
        </button>
    </div>
    <script>
        var duration = 300;
    
        $('#buttons2 button')
            .on('mouseover', function(){
                var $btn = $(this);
                $btn.animate ({
                    backgroundColor: '#faee00',
                    color: '#000'
                }, duration);
                $btn.find('p:first-child').animate({opacity: 0}, duration);
                $btn.find('p:nth-child(2)').animate({opacity: 1}, duration);
            })
            .on('mouseout', function(){
                var $btn = $(this);
                $btn.animate({
                    backgroundColor: '#fff',
                    color: '#01b169',
                }, duration);
                $btn.find('p:first-child').stop(true).animate({opacity: 1}, duration);
                $btn.find('p:nth-child(2)').stop(true).animate({opacity: 0}, duration);
            });
    </script>
    </body>
    </html>
    
[/code]

## 質問

このような無限ループが発生する原因を教えていただきたいです．

よろしくお願いいたします．


CC BY-SA 4.0
2022-06-10T09:34:19.563
89319
2022-06-13T02:13:30.183
53010
question
javascript jquery jquery-ui
jQueryとjQuery UI でアニメをさせたところ，何故か無限に繰り返してしまう


mouseoverとmouseoutが実行した分繰り返されているだけで無限ループではないです。  
それぞれの仕様を確認してみましょう。  
ポイントは「バブリング」のありなしです。

  * [mouseover](https://developer.mozilla.org/ja/docs/Web/API/Element/mouseover_event)
  * [mouseout](https://developer.mozilla.org/ja/docs/Web/API/Element/mouseout_event)

[バブリング](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling_and_capture)はイベント周りでは重要な要素になるので是非学んでおいてください。  
簡単にいえば「子要素のイベントが親要素にも伝搬する」

つまりはbuttonに設定したmouseoverやmouseoutは子要素のmouseoverやmouseoutも検知してイベントが発火します。  
そのため、animateで要素の表示非表示をすると交互にmouseoverやmouseoutが発生します。

時系列に並べると

ボタンにマウスを合わせる  
→buttonのmouseover発火  
`<p>`にマウスを合わせる  
→buttonのmouseoutが発生  
→pのmouseoverが発生  
→pの要素が入れ替わる(animate)  
→pのmouseoutが発生  
→pの要素が入れ替わる  
→pのmouseoverが発生  
→pの要素が入れ替わる  
→以下ループ

入れ替わるたびにmouseoverとmouseoutが発生しています。

バブリングしたくないのであればmouseenterとmouseleaveを利用しましょう。

  * [mouseenter](https://developer.mozilla.org/ja/docs/Web/API/Element/mouseenter_event)
  * [mouseleave](https://developer.mozilla.org/ja/docs/Web/API/Element/mouseleave_event)

[code]

    var duration = 300;
    
        $('#buttons2 button')
            .on('mouseenter', function(){
                var $btn = $(this);
                $btn.animate ({
                    backgroundColor: '#faee00',
                    color: '#000'
                }, duration);
                $btn.find('p:first-child').animate({opacity: 0}, duration);
                $btn.find('p:nth-child(2)').animate({opacity: 1}, duration);
            })
            .on('mouseleave', function(){
                var $btn = $(this);
                $btn.animate({
                    backgroundColor: '#fff',
                    color: '#01b169',
                }, duration);
                $btn.find('p:first-child').stop(true).animate({opacity: 1}, duration);
                $btn.find('p:nth-child(2)').stop(true).animate({opacity: 0}, duration);
            });
[/code]

[code]

    #buttons2 button p:first-child {
      position: absolute;
    }
    #buttons2 button p:nth-child(2) {
      opacity: 0;
    }
[/code]

[code]

    <div id="buttons2">
        <button>
            <p>hogehoge</p>
            <p>mokemoke</p>
        </button>
    </div>
        <script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
[/code]


CC BY-SA 4.0
2022-06-13T01:05:30.137
89360
2022-06-13T02:13:30.183
2022-06-13T02:13:30.183
3060
22665
89319
answer