リストを入れ子にしたグローバルメニュー

前回記事の jQuery でもアロー関数とthisを使いたい の内容を使ってドロップダウンする入れ子になったグローバルメニューリストを先輩にアドバイスもらいながら実装したのでその覚書です。

参考にしたサイト

グローバルメニューリストを実装するにあたって、下の画像の ブランドサイト | a-blog cms (スマホ幅の時のオフキャンバス)を参考にしました。<ul><li> を入れ子にした実装になっています。



実装内容

上記サイトを参考にしながらこのようなドロップダウンメニューを作りました。

ソースコード

HTML

<div class="test-nav">
  <ul class="test-nav-list">
    <li class="js-test-nav-toggle test-nav-item">
      <a class="test-nav-item__link" href="https://example.com/example1/" target="">リンク1</a>
    </li>
    <li class="js-test-nav-toggle test-nav-item">
      <a class="test-nav-item__link  " href="" target="">リンク2(ドロップダウン)</a>
      <ul>
        <li class="js-test-nav-toggle test-nav-item">
          <a class="test-nav-item__link" href="https://example.com/example2/example2-1.html" target="">リンク2-1</a>
        </li>
        <li class="js-test-nav-toggle test-nav-item">
          <a class="test-nav-item__link" href="" target="">リンク2-2(ドロップダウン)</a>
          <ul>
            <li class="js-test-nav-toggle test-nav-item">
              <a class="test-nav-item__link" href="https://example.com/example2/example2-2-1.html" target="">リンク2-2-1</a>
            </li>
            <li class="js-test-nav-toggle test-nav-item">
              <a class="test-nav-item__link" href="https://example.com/example2/example2-2-2.html" target="">リンク2-2-2</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</div>

CSS

<style>
.test-nav {
  box-sizing: border-box;
  width: 300px;
  max-width: 100%;
  margin: 30px 0;
  padding: 0 10px;
}

.test-nav-list,
.test-nav-list ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.test-nav-item {
  margin: 0; /* 打ち消し */
  padding: 0;
  color: #666;
}

.test-nav-item__link {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  padding: 10px 20px 10px 10px;
  color: #666;
  border-bottom: 1px solid #666;
}

.test-nav-item__link,
.test-nav-item__link:link,
.test-nav-item__link:hover,
.test-nav-item__link:visited,
.test-nav-item__link:active,
.test-nav-item__link:focus {
  color: inherit;
  text-decoration: none;
}

.offcanvasListExpandable > ul {
  display: none;
}

.offcanvasListExpandable > a::after {
  content: "∨";
  position: absolute;
  top: calc(50% - 7px);
  right: 10px;
  font-weight: bold;
  font-size: 14px;
  line-height: 1;
}

.offcanvasListExpandable.active > a::after {
  content: "∧";
}
</style>

jQuery

<script>
  $(function(){
    $('.js-test-nav-toggle').each((index, element) => {
      const $item = $(element);
      const listChildren = $item.children('ul');
      if (listChildren.length) {
        $item.addClass('offcanvasListExpandable');
      }
    });

    $('.offcanvasListExpandable').click((event) => {
      const $that = $(event.currentTarget);
      if ($that.hasClass('offcanvasListExpandable') && !$(event.target).attr('href')) {
        const $ul = $that.children('ul');
        if (!$that.hasClass('active')) {
          $that.addClass('active');
          $ul.slideToggle();
        } else {
          $ul.slideToggle(() => {
            $that.removeClass('active');
          });
        }
        return false;
      }
      return true;
    });
  });
</script>

ポイント

  • jQuery でもアローファンクションを使っている
  • !$(event.target).attr('href') することで入れ子の入れ子にも対応
  • return false; で preventDefault() と stopPropagation()

参考サイト


タグ