LoginSignup
0
0

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

Posted at

完成系

こんな感じになりました!(CSSで装飾一切なし...;( ˙꒳ ˙ ;):
kansei.gif
今回はHTMLで記述をしますが、実際は投稿されている情報を取ってきて、コンテンツを表示してます。
※今回はCMS(WordPress)から情報を取ってくることにしました。

ロジックについて

  • selectボックス

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

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

まずは簡単にHTMLとCSSを書いていく

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
/* 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

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で何か作ってみる(✧ω✧)

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0