60948


ヘッダーにメガメニューを実装しようとしています。

下記スニペットのような実装をしているのですが、

  * 初めて.nav（または.nav__item）をホバーした場合はslideDownで開く
  * .nav内でかつ.nav__itemを行き来する場合はfadeInとhideで切り替え
  * .navのエリアから出た場合はslideUpで閉じる

ということがやりたいです。

.nav内にいる場合は.navに.is-activeを付与して  
is-activeがあれば.nav__itemをfadeIn,hideする  
なければ.nav__itemをslideDown,slideUpする

上記の考えで大丈夫だと思っていましたが、.navを出た際にis-activeが消えるより早くitemのhideが実行されてしまいました。

delayやsetTimeoutでタイミングをずらせば出来そうではありますが、  
あまりそういうことはやりたくないと感じました。

何か良い実装方法はありますでしょうか。  
ご回答のほど、よろしくお願いいたします。

[code]

    $(function(){
      const $nav = $('.nav');
      const $item = $('.nav__item');
    
      $nav.hover(
        function(){
          $nav.addClass('is-active');
        },
        function(){
          $nav.removeClass('is-active');
        }
      );
    
      $item.hover(
        function (){
          const $this = $(this);
          if($nav.hasClass('is-active')) $this.find('.megamenu__body:not(:animated)').fadeIn();
          else $this.find('.megamenu__body:not(:animated)').slideDown();
        },
        function (){
          const $this = $(this);
          if($nav.hasClass('is-active')) $this.find('.megamenu__body:not(:animated)').hide();
          else $this.find('.megamenu__body:not(:animated)').slideUp();
        }
      );
    });
[/code]

[code]

    body {
      margin: 0;
      padding: 0;
    }
    
    .nav {
      display: flex;
    }
    .nav__item {
      flex: 1 1 auto;
      height: 50px;
      border: 1px solid #000;
    }
    .nav__item:hover {
      background: gray;
    }
    
    .megamenu {
      background: blue;
      position: absolute;
      top: 50px;
      right: 0;
      left: 0;
    }
    .megamenu__body {
      display: none;
      height: 100px;
      background: blue;
      color: white;
    }
[/code]

[code]

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="nav">
      <div class="nav__item">itemA
        <div class="megamenu">
          <div class="megamenu__body">contentA</div>
        </div>
      </div>
      <div class="nav__item">itemB
        <div class="megamenu">
          <div class="megamenu__body">contentB</div>
        </div>
      </div>
    </div>
[/code]


CC BY-SA 4.0
2019-11-29T14:39:07.717
60946
2019-11-29T17:50:26.187
30065
question
javascript html jquery css
メガメニューのトグルがうまく行かない


今回の場合イベントの伝播を制御しようとするとかえって複雑になりそうなので、月並みな方法ですが、 `is` メソッドで `$nav`
がホバーされているかどうかを確認し、それを都度変数へ保存しておくという方法が代替として考えられます。

[code]

    $(function() {
      const $nav = $('.nav');
      const $item = $('.nav__item');
      let isNavHovered = $nav.is(':hover');
    
      $item.hover(
        function() {
          const $megamenu = $(this).find('.megamenu__body').stop(true, true);
          if (isNavHovered) $megamenu.fadeIn();
          else $megamenu.slideDown();
          isNavHovered = $nav.is(":hover");
        },
        function() {
          if ($nav.is(":hover")) $(this).find('.megamenu__body').stop(true, true).hide();
          else $nav.find('.megamenu__body').stop(true, true).slideUp();
          isNavHovered = $nav.is(":hover");
        }
      );
    });
    
[/code]

[code]

    $(function() {
      const $nav = $('.nav');
      const $item = $('.nav__item');
      let isNavHovered = $nav.is(':hover');
    
      $item.hover(
        function() {
          const $megamenu = $(this).find('.megamenu__body').stop(true, true);
          if (isNavHovered) $megamenu.fadeIn();
          else $megamenu.slideDown();
          isNavHovered = $nav.is(":hover");
        },
        function() {
          if ($nav.is(":hover")) $(this).find('.megamenu__body').stop(true, true).hide();
          else $nav.find('.megamenu__body').stop(true, true).slideUp();
          isNavHovered = $nav.is(":hover");
        }
      );
    });
[/code]

[code]

    body {
      margin: 0;
      padding: 0;
    }
    
    .nav {
      display: flex;
    }
    
    .nav__item {
      flex: 1 1 auto;
      height: 50px;
      border: 1px solid #000;
    }
    
    .nav__item:hover {
      background: gray;
    }
    
    .megamenu {
      background: blue;
      position: absolute;
      top: 50px;
      right: 0;
      left: 0;
    }
    
    .megamenu__body {
      display: none;
      height: 100px;
      background: blue;
      color: white;
    }
[/code]

[code]

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="nav">
      <div class="nav__item">itemA
        <div class="megamenu">
          <div class="megamenu__body">contentA</div>
        </div>
      </div>
      <div class="nav__item">itemB
        <div class="megamenu">
          <div class="megamenu__body">contentB</div>
        </div>
      </div>
    </div>
[/code]


CC BY-SA 4.0
2019-11-29T17:50:26.187
60948
2019-11-29T17:50:26.187
32986
60946
answer