「selectボックス＋もっと見るボタン」で絞り込みロジックをJavaScriptでぱぱっと作ってみた

## 完成系
こんな感じになりました！(CSSで装飾一切なし...;( ˙꒳ ˙ ;):
![kansei.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2708799/6130dfdf-9c1b-91a4-5ca5-e8a79ea83039.gif)
今回はHTMLで記述をしますが、実際は投稿されている情報を取ってきて、コンテンツを表示してます。
※今回はCMS（WordPress）から情報を取ってくることにしました。

## ロジックについて
- selectボックス
    - selectボックスで選択をし、選択したらコンテンツを切り替える
    - selectボックスは1番上に「全て」を配置し、「全て」を選択したら全て表示にする
    - コンテンツに紐づいている「カテゴリ」で絞り込みが出来るようにする
    - 特定のカテゴリを選ばれた状態でページを遷移してくる可能性もあるので、URLフラグメントで対応する

- もっと見るボタン
    - 4件以上の時はもっと見るボタンを活性化する
    - もっと見るボタンを押すごとに、4件ずつ表示されるようにする
    - 表示する記事がなくなったら非活性にする

## まずは簡単にHTMLとCSSを書いていく
```html:html
<select id="select" name="cat" class="js-filter" onchange="location.hash=value">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
</select>
<div class="js-filter-items">
    <div class="list-item js-filter-item" data-cat="1">
        <p class="aBusiness-Lineup__label">カテゴリー1のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="3">
        <p class="aBusiness-Lineup__label">カテゴリー3のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="3">
        <p class="aBusiness-Lineup__label">カテゴリー3のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="2">
        <p class="aBusiness-Lineup__label">カテゴリー2のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="1">
        <p class="aBusiness-Lineup__label">カテゴリー1のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="1">
        <p class="aBusiness-Lineup__label">カテゴリー1のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="2">
        <p class="aBusiness-Lineup__label">カテゴリー2のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="1">
        <p class="aBusiness-Lineup__label">カテゴリー1のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="1">
        <p class="aBusiness-Lineup__label">カテゴリー1のコンテンツ</p>
    </div>
    <div class="list-item js-filter-item" data-cat="3">
        <p class="aBusiness-Lineup__label">カテゴリー3のコンテンツ</p>
    </div>
    <button id="moreRead" type="button" class="m-Btn">もっと見る</button>
</div>
```

```css:css
/* select */
.js-filter-item.is-hide {
    opacity: 0;
}
.js-filter-item.is-hide-anime {
    display: none;
}
.js-filter-item {
    transition: opacity 150ms;
    opacity: 1;
}

/* more button */
.js-filter-item.hidden {
    display: none;
}
```

## JavaScript

```js:JavaScript
let showLengthNum = 4;
let showLength = showLengthNum;
const moreHiddenClass = 'hidden';
const showClass = 'is-show';
const addBtn = document.querySelector('#moreRead');
const targetItem = '.list-item';
const classIsHide = 'is-hide';
const classIsHideAnime = 'is-hide-anime';

//セレクト
const multiFilter = (hideClass, hideClassAnime, target, select = '') => {
    const hidden = hideClass;
    const hiddenAnime = hideClassAnime;
    const targets = document.querySelectorAll(target);
    const selects = document.querySelectorAll(select);
    const option = document.getElementById('select').options;
    if (selects) {
        for (let i of selects) {
            //ハッシュタグがあったら
            if(location.hash) {
                //hashと同じselectをselected
                for (let j of option) {
                    j.selected = false;
                    if(location.hash === '#' + j.value) {
                        j.selected = true;
                    }
                }
            }
            //selectを変更した時
            i.addEventListener('change', () => {
                let hiddenNum = 0;
                for (let j of targets) {
                    j.classList.remove(hidden);
                    j.classList.remove(moreHiddenClass);
                    j.classList.add(showClass);
                    setTimeout(() => {
                        j.classList.remove(hiddenAnime);
                    }, 100);
                    for (let k of selects) {
                        const value = k.value;
                        const name = k.getAttribute('name');
                        const itemData = j.getAttribute('data-' + name);
                        if (value && value !== 'all' && value !== itemData && !j.classList.contains(hidden)) {
                            j.classList.add(hidden);
                            j.classList.remove(showClass);
                            setTimeout(() => {
                                j.classList.add(hiddenAnime);
                            }, 100);
                            hiddenNum++;
                        }
                    }
                }
                //もっと見るボタンがある場合
                if(addBtn) {
                    showLength = showLengthNum;   //再度代入
                    let hiddenItemTarget = document.querySelectorAll(targetItem + '.' + showClass);
                    if (hiddenItemTarget.length > showLength) {
                        for (let i = showLength; i < hiddenItemTarget.length; i++) {
                            hiddenItemTarget[i].classList.add(moreHiddenClass);
                        }
                    }
                    addBtn.disabled = false;
                    if (document.querySelectorAll(targetItem + '.' + moreHiddenClass).length == 0) {
                        addBtn.disabled = true;
                    }
                }
            });
        }
    }
}
multiFilter(classIsHide, classIsHideAnime, '.js-filter-item', '.js-filter');

//もっと見るボタン
const moreBtn = () => {
    const targets = document.querySelectorAll('.list-item');
    if(addBtn) {
        window.addEventListener('DOMContentLoaded', () => {
            //hashがある場合
            if(location.hash) {
                const selects = document.querySelectorAll('.js-filter');
                for (let j of targets) {
                    j.classList.add(classIsHide);
                    j.classList.add(classIsHideAnime);
                    j.classList.remove(moreHiddenClass);

                    for (let k of selects) {
                        const value = k.value;
                        const name = k.getAttribute('name');
                        const itemData = j.getAttribute('data-' + name);
                        if(location.hash === '#' + itemData) {
                            j.classList.add(showClass);
                            j.classList.remove(classIsHide);
                            j.classList.remove(classIsHideAnime);
                        }
                        if(value === 'all') {
                            j.classList.add(showClass);
                            j.classList.remove(classIsHide);
                            j.classList.remove(classIsHideAnime);
                        }
                    }
                }
                let chooseTarget = document.querySelectorAll(targetItem + '.' + showClass);
                if (chooseTarget.length > showLength) {
                    for (let i = showLength; i < chooseTarget.length; i++) {
                        chooseTarget[i].classList.add(moreHiddenClass);
                    }
                } else {
                    addBtn.disabled = true;
                }
            } else {
                let targetsLength = targets.length;
                if (targetsLength > showLength) {
                    for (let i = showLength; i < targetsLength; i++) {
                        targets[i].classList.add(moreHiddenClass);
                    }
                } else {
                    addBtn.disabled = true;
                }
            }
        });

        addBtn.addEventListener('click', () => {
            let hiddensTarget = document.querySelectorAll(targetItem + '.' + moreHiddenClass);
            if (hiddensTarget.length < showLength) {
                showLength = hiddensTarget.length;
            }
            for (let i = 0; i < showLength; i++) {
                hiddensTarget[i].classList.remove(moreHiddenClass);
            }
            if (document.querySelectorAll(targetItem + '.' + moreHiddenClass).length == 0) {
                addBtn.disabled = true;
            }
        });
    }
}
moreBtn();
```
見た目以上に処理が複雑になってしまった( ˘•_•˘ )
でもJavaScriptだけで実装が出来て良かった！

時間がある時に改修できたらいいなー

次はTypeScriptで何か作ってみる(✧ω✧)