データ属性とJSで絞り込み(AND)検索
6分データ属性と JS で絞り込み検索作った
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./index.css" />
<script src="./index.js"></script>
<title>Document</title>
</head>
<body>
<ul class="filters">
<li>
<button class="js-item-term" data-term="お菓子">お菓子</button>
</li>
<li>
<button class="js-item-term" data-term="酒">酒</button>
</li>
<li>
<button class="js-item-term" data-term="調味料">調味料</button>
</li>
<li>
<button class="js-item-term" data-term="ANIMAL">ANIMAL</button>
</li>
<li>
<button class="js-item-term" data-term="肉">肉</button>
</li>
<li>
<button class="js-item-term" data-term="ニンニク">ニンニク</button>
</li>
<li>
<button class="js-item-term" data-term="魚">魚</button>
</li>
<li>
<button class="js-item-term" data-term="野菜">野菜</button>
</li>
<li>
<button class="js-item-term" data-term="卵">卵</button>
</li>
<li>
<button class="js-item-term" data-term="お寿司">お寿司</button>
</li>
<li>
<button class="js-item-term" data-term="嬉しい">嬉しい</button>
</li>
</ul>
<ul class="products">
<li class="js-item" data-tag="魚,お寿司,ANIMAL, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">えんがわ握り</span>
<ul class="products__box--tags">
<li>魚</li>
<li>お寿司</li>
<li>ANIMAL</li>
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="野菜">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">もやし</span>
<ul class="products__box--tags">
<li>野菜</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="お菓子, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">グミ</span>
<ul class="products__box--tags">
<li>お菓子</li>
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="調味料">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">塩</span>
<ul class="products__box--tags">
<li>調味料</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="肉,ANIMAL, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">焼肉</span>
<ul class="products__box--tags">
<li>肉</li>
<li>ANIMAL</li>
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="酒, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">スト缶</span>
<ul class="products__box--tags">
<li>酒</li>
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="酒, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">ビール</span>
<ul class="products__box--tags">
<li>酒</li>
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="ニンニク, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">ニンニク</span>
<ul class="products__box--tags">
<li>ニンニク</li>
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">現金</span>
<ul class="products__box--tags">
<li>嬉しい</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="肉">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">お惣菜</span>
<ul class="products__box--tags">
<li>肉</li>
</ul>
</div>
</li>
<li class="js-item" data-tag="肉, ANIMAL, 嬉しい">
<div class="products__box">
<img src="https://placehold.jp/150x100.png" alt="" />
<span class="products__box--title">鶏皮ポン酢</span>
<ul class="products__box--tags">
<li>肉</li>
<li>ANIMAL</li>
<li>嬉しい</li>
</ul>
</div>
</li>
</ul>
</body>
</html>
// variables
$wrap: 560px;
$gapY: 20px;
// reset
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
// 共通
.filters,
.products {
display: flex;
flex-wrap: wrap;
margin: $gapY auto 0;
max-width: $wrap;
width: 100%;
& > li {
margin: 10px;
}
}
// ボタン
.filters {
button {
appearance: none;
background: #4082f0;
border: none;
border-radius: 30px;
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.59);
color: #fff;
cursor: pointer;
font-size: 12px;
line-height: 15px;
min-width: 120px;
padding: 1em;
transform: translateY(-2px);
transition: all 0.2s;
&.active,
&:hover {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.79);
transform: none;
}
&.active {
background: #15366d;
}
}
}
// 商品部分
.products {
border-top: 1px solid #f6f6f6;
padding-top: 20px;
& > li {
width: calc((100% - (10px * 6)) / 3);
}
&__box {
border: 1px solid #cacaca;
display: flex;
flex-direction: column;
padding: 8px;
&--title {
color: #444;
font-size: 0.9em;
margin-top: 10px;
}
&--tags {
font-size: 10px;
li {
color: #888;
display: inline-block;
&::before {
color: #4082f0;
content: "#";
opacity: 0.5;
padding-right: 2px;
}
&:not(:first-child) {
margin-left: 6px;
}
}
}
}
}
// 表示/非表示
.js-item {
animation: fadeInItem 0.5s both;
will-change: opacity, width;
&.fadeOut {
animation: fadeOutItem 0.5s both;
.products__box {
display: none;
}
}
}
@keyframes fadeInItem {
0% {
margin: 0;
opacity: 0;
padding: 0;
width: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOutItem {
0% {
opacity: 1;
}
100% {
display: none;
margin: 0;
opacity: 0;
padding: 0;
width: 0;
}
}
"use strict";
window.addEventListener("load", function() {
const d = document;
const items = d.querySelectorAll(".js-item");
const terms = [];
const buttons = d.querySelectorAll(".js-item-term");
for (const button of buttons) {
button.addEventListener("click", function() {
button.classList.toggle("active");
// クリックした条件を絞り込み条件リストに追加/削除
const term = button.getAttribute("data-term");
const termPosition = terms.indexOf(term);
if (termPosition !== -1) {
terms.splice(termPosition, 1);
} else {
terms.push(term);
}
console.log("terms: ", terms);
// 絞り込み
for (const item of items) {
// 選択されてる条件ないなら全てのfadeOut取って処理終了
if (terms.length === 0 && item.classList.contains("fadeOut")) {
item.classList.remove("fadeOut");
continue;
}
// 空白削除して配列に
const itemTagsArray = item
.getAttribute("data-tag")
.replace(/\s+/g, "")
.split(",");
const isIncludedTerm = terms.filter(function(term) {
return itemTagsArray.indexOf(term) !== -1;
});
if (isIncludedTerm.length !== terms.length && !item.classList.contains("fadeOut")) {
// 現在の条件と完全一致してなくてfadeOutクラスもなければfadeOutクラス付与
item.classList.add("fadeOut");
} else if (isIncludedTerm.length === terms.length && item.classList.contains("fadeOut")) {
// 現在の条件と完全一致しててfadeOutクラスあるならfadeOutクラス外す
item.classList.remove("fadeOut");
}
}
});
}
});