MultiSelectFilter

by interlife

HTML

<div class="tab_wrap">
  <dl class="tab_head">
    <dt>絞り込み</dt>
    <dd>
      <ul id="js_tab_nav" class="tab_nav">
        <li><a class="tab_item" data-tag="tag1">桃</a></li>
        <li><a class="tab_item" data-tag="tag2">レモン</a></li>
        <li><a class="tab_item" data-tag="tag3">メロン</a></li>
      </ul>
    </dd>
  </dl>
  <ul id="js_tab_contents" class="tab_contents">
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag1">桃</li>
        <li class="tag2">レモン</li>
        <li class="tag3">メロン</li>
      </ul>
    </li>
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag1">桃</li>
        <li class="tag2">レモン</li>
      </ul>
    </li>
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag1">桃</li>
      </ul>
    </li>
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag2">レモン</li>
        <li class="tag3">メロン</li>
      </ul>
    </li>
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag2">レモン</li>
      </ul>
    </li>
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag1">桃</li>
        <li class="tag3">メロン</li>
      </ul>
    </li>
    <li class="tab_item">
      <ul class="tag_list">
        <li class="tag3">メロン</li>
      </ul>
    </li>
  </ul>
</div>

SCSS

.tab_wrap {
  margin: 2em auto;
  width: 80%;
}
.tab_head {
  text-align: center;
  dt {
    line-height: 1;
    font-size: 18px;
    font-weight: bold;
  }
  .tab_nav {
    margin-top: 1em;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    width: 100%;
    .tab_item {
      margin: 0 2px;
      padding: 2px 18px;
      border: solid 2px #000;
      border-radius: 15px;
      display: inline-flex;
      align-items: center;
      cursor: pointer;

      &:hover,
      &.active {
        border: solid 2px #ffd100;
        outline: solid 2px #ff8500;
      }
    }
  }
}
.tab_contents {
  margin: 2em auto;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  > li {
    margin-bottom: 1em;
    padding: 1em;
    border-radius: 5px;
    border: solid 1px #000;
    display: flex;
    align-items: flex-start;
    position: relative;
    width: 32%;
    background: #f4f4f4;
    box-sizing: border-box;
  }
  .tag_list {
    display: flex;
    flex-direction: column;
    font-size: 1.4vw;
    li {
      margin: 0 2px 5px;
      padding: 2px 1em;
      border: solid 1px #000;
      border-radius: 15px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      white-space: nowrap;
    }
  }
}

JavaScript

// activeになっているtagを格納するための配列を用意
  let activeTagArray = new Array();
  // #js_tab_nav .tab_item のいずれかをクリックしたら
  $('#js_tab_nav .tab_item').on('click', function() {
    //クリックした要素の「data-tag="xxxx"」を取得して変数に格納
    const tagData = $(this).data('tag');
    //クリックした要素の"active"をtoggle
    $(this).toggleClass("active");
    //toggleした結果、クリックした要素がactiveを持っていたら、配列にtagDataを追加
    if($(this).hasClass("active")) {
      activeTagArray.push(tagData);
    //toggleした結果、クリックした要素がactiveを持っていなかったら、配列からtagDataを削除
    } else {
      activeTagArray = activeTagArray.filter(function( item ) {
        return item !== tagData;
      });
    }
    // #js_tab_contents .tab_item を 変数「contentTabItem」に格納する
    const contentTabItem = $('#js_tab_contents .tab_item');
    // contentTabItem を、一旦全て非表示
    contentTabItem.hide();
    // 配列activeTagArrayに格納されている「tag」を含む contentTabItem を表示させる
    activeTagArray.forEach(function(val){
      contentTabItem.has('.'+val).show();
    });
    // 配列activeTagArrayが空の場合(クリックした後、active要素がひとつもない場合)、全てのcontentTabItemを表示
    if(!activeTagArray.length) {
      contentTabItem.show();
    } 
  });