もっと見るボタン

Web

JSでもっと見るボタンを実装する

もっと見るボタンの話があり、調べた時の話。発見があったので、メモ。初めてのもっと見るボタンの実装。実際はjQueryでという指示だったので、下記を参考にしました。なかなかいい感じで、これだけ短いコードで実装できるのはjQueryの魅力ですよね。一方で、脱jQueryという流れもあり、普通のJSで書けるか、ちょっとやってみた方が良いなと思い、やってみました。結果的にはなんとか動きました。

n件ずつ表示する「もっと見る」ボタンのシンプル実装 - Qiita
私はなぜか「もっと見る」ボタンを実装することがやたらと多いので、いろいろなやり方を試す中で「これが一番シンプル!」と発見…

index.html、reset.cssとstyle.css、そして、main.jsが構成要素です。HTMLは雛形HTMLに、要素を並べるdivともっと見るのbuttonを追加しただけ。reset.cssの掲載はありませんが、好みが分かれると思うので、お好みで。

<!DOCTYPE html>
<html lang="ja" xml:lang="ja" xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="keywords" content="" />
    <meta name="description" content="" />
    <title>タイトル</title>
    <link rel="stylesheet" href="reset.css" />
    <link rel="stylesheet" href="style.css" />
    <style></style>
  </head>
  <body>
    <main>
      <article>
        <h1>List</h1>
        <div class="json__list">
        </div>
        <button class="btn__more">
          もっと見る
        </button>
      </article>
    </main>
    <script src="main.js"></script>
    <script></script>
  </body>
</html>

style.cssも結構適当です。短くするため、横に並べました。最後の行で、要素が無い場合、クラスを付与し、ボタンがフェードして消える形を踏襲しています。

body { padding: 2em; }
img { width: 100%; height: 100%; }
h1 { margin-bottom: 1em; font-size: 2em; text-align: center; }
.json__list { display: flex; flex-wrap: wrap; }
.list__box { display: flex;  width: calc(100% / 4); margin-right: 2em; margin-bottom: 2em; }
.list__wrap { display: flex; width: 100%; margin-right: 1em; }
.listImg__wrap { width: 100px; height: auto; margin-right: 1em; }
.listTxt__ttl { margin-bottom: 0.5em; font-size: 1.4em; font-weight: bold; }
.btn__more { padding: 0.5em; background: #000; color: #fff; transition: all 1s; }
.btn__more.is__out { opacity: 0; visibility: hidden; }

jsが長いので、編集の都合により、分割します。本来は下記すべて、main.jsに記載されています。前半は要素を納めるdivとボタンといった必要な要素の取得、要素を納める配列の用意。そして、表示する数を設定しています。ローカルではダミーのapiからデータをとってきたので、その流れでfetchしている形です。後半にはデータの読み込み(getData())と表示する仕組み(displayList())の関数があります。ボタンをクリックすると指定の数だけ表示され、表示する数より残りの配列が少なければ、ボタンにクラスが付与され、消えます。

const listArea = document.querySelector(".json__list");
const btnMore = document.querySelector(".btn__more");
let list = new Array();
const displayNum = 10;

getData()
  .then((list) => {
    displayList(list, displayNum);

    btnMore.addEventListener("click", () => {
      if (list.length > displayNum) {
        displayList(list, displayNum);
      } else if (list.length < displayNum) {
        btnMore.classList.add("is__out");
        displayList(list, list.length);
      }
    });
  })
  .catch((err) => {
    console.log(err);
  });

getData()はfetchでデータを読み込みます。urlはダミーです。データをとって来る時に、同期・非同期の関係でデータがわちゃわちゃになり、苦労しましたが、なんとか順番通り表示することができました。displayList()ではデータと数を引数にして、引数の数だけデータを抽出し、その分だけ、データを先頭から削除しています。その後、抽出したデータの数だけ、mapでHTML化し、要素が並ぶdivに挿入。このやり方で大丈夫かって問題はありますが、正直わかりません。気になった点と言えば、innerHTMLと外部apiを使っていたので、エスケープした方がよかったんでしょうね。まあ、参考ということで。

async function getData() {
  const data = await fetch(
    "https://url"
  );
  return await data.json();
}

async function displayList(list, num) {
  const currentList = list.slice(0, num);
  list.splice(0, num);
  const box = await currentList
    .map((list) => {
      return `
      <section class="list__box">
        <figure class="opacityTargets" class="listImg__wrap">
          <img src="${list.image}" alt="${list.title}" class="listImg__img" />
        </figure class="opacityTargets">
        <div class="listTxt__wrap">
          <h2 class="listTxt__ttl">${list.title}</h2>
          <p class="listTxt__txt">${list.text}</p>
        </div>
      </section>
    `;
    })
    .join("");
  listArea.innerHTML += box;
}

コメント