jsで簡易的なソート機能を実装。

2025/03/04に公開

概要

html直書きのデータを参照して、ソートしてくれる機能を実装しました。

  <div class="item">
    <h3>アンドロイドタブレット</h3>←これは何でもよい
         
    <div class="price">45000</div>
    <div class="spec">150000</div>
  </div>

これが基本単位。

jsのコードを変更すればパラメータは増やせるので、適宜変更してください。

今回は、データベースを使わずに、だれでもコンテンツのソートができるものを作りました。

速度等は一切考慮していません。

データは基本的に数値型。
円表記はしないでください。

表示が煩わしい場合は、

  <div class="item">
    <div class="price" style = "display:none;">45000</div>
    <div class="spec" style = "display:none;">150000</div>
  </div>

動的に読み込むようなものは考慮していません。
動的にサーバーからデータを取得できる方は
そもそもソート機能を実装できるからです。

今回の対象は、ホームページを運営しているが、jsはあまり触れたことがない方用です。

テストがしやすいように単一ファイルで張り付けておきます


<!DOCTYPE html>
<html>
<head>
  <style>
    .item { border: 1px solid #ccc; padding: 10px; margin: 5px; }
    .controls { margin: 20px 0; padding: 10px; background: #f5f5f5; }
    .filter-group { margin-right: 20px; }
  </style>
  
</head>

<!--
動作要件
HTMLに事前にitem要素が存在する必要があります
各item要素は正しいclass構成(priceとspec)を持っている必要があります
sort_content要素がページ内に存在する必要があります
拡張する場合のヒント
動的にitem要素を追加する場合は、追加後にinitializeData()を再実行
データ更新時はoriginalData配列を直接更新
サーバーサイドからのデータ取得が必要な場合は、fetch後にDOM要素を生成してから初期化処理を実行


-->
<body>
  <!-- コントロールパネル -->
  <div class="controls">
    <div class="filter-group">
      ソートキー:
      <select id="sortKey">
        <option value="price">価格</option>
        <option value="spec">スペック</option>
      </select>
    </div>

    <div class="filter-group">
      ソート順:
      <select id="sortOrder">
        <option value="asc">昇順</option>
        <option value="desc">降順</option>
      </select>
    </div>

    <div class="filter-group">
      価格範囲:
      <input type="number" id="minPrice" placeholder="最小価格"><input type="number" id="maxPrice" placeholder="最大価格">
    </div>

    <div class="filter-group">
      スペック範囲:
      <input type="number" id="minSpec" placeholder="最小スペック"><input type="number" id="maxSpec" placeholder="最大スペック">
    </div>

    <button onclick="updateDisplay()">適用</button>
  </div>
<!-- データコンテナのHTML例 -->
<div id="sort_content">
  <div class="item">
    <div class="price">30000</div>
    <div class="spec">100000</div>
  </div>
  <div class="item">
    <div class="price">45000</div>
    <div class="spec">150000</div>
  </div>
  <!-- その他のitem要素 -->
</div>


  <!-- データ表示領域 -->
  <div id="container"></div>

  <script>

    // 初期データ保持用変数
  let originalData = [];


  // データ初期化(sort_contentから取得)
  const initializeData = () => {
    const container = document.getElementById('sort_content');
    originalData = [];
    
    // 既存のitem要素を取得
    const items = container.getElementsByClassName('item');
    
    Array.from(items).forEach(item => {
      // 元データを保持(DOM要素と数値データを紐付け)
      originalData.push({
        element: item.cloneNode(true), // クローンを保持
        price: parseInt(item.querySelector('.price').textContent),
        spec: parseInt(item.querySelector('.spec').textContent)
      });
    });

    // 初期表示用にコンテナをクリア
    container.innerHTML = '';
  };

  // データ取得関数
  const getItemsData = () => {
    return originalData.map(data => ({...data})); // ディープコピー
  };

  // 表示更新
  const updateDisplay = () => {
    const container = document.getElementById('sort_content');
    const sortKey = document.getElementById('sortKey').value;
    const sortOrder = document.getElementById('sortOrder').value;
    
    let data = getItemsData();
    data = filterItems(data);
    data = sortItems(data, sortKey, sortOrder);

    container.innerHTML = '';
    data.forEach(item => {
      container.appendChild(item.element.cloneNode(true));
    });
  };



// ソート処理
const sortItems = (data, key, order) => {
  return data.sort((a, b) => {
    const modifier = order === 'asc' ? 1 : -1;
    return (a[key] - b[key]) * modifier;
  });
};
/*
    // フィルタリング処理
    const filterItems = (data) => {
      const minPrice = parseInt(document.getElementById('minPrice').value) || -Infinity;
      const maxPrice = parseInt(document.getElementById('maxPrice').value) || Infinity;
      const minSpec = parseInt(document.getElementById('minSpec').value) || -Infinity;
      const maxSpec = parseInt(document.getElementById('maxSpec').value) || Infinity;

      return data.filter(item => 
        item.price >= minPrice &&
        item.price <= maxPrice &&
        item.spec >= minSpec &&
        item.spec <= maxSpec
      );
    };
*/
//上の方法だとうまくいかないので以下にしました
      // フィルタリング処理(改修版)
  const filterItems = (data) => {
    // 価格範囲の処理
    const minPriceInput = document.getElementById('minPrice');
    const maxPriceInput = document.getElementById('maxPrice');
    const minPrice = minPriceInput.value !== '' 
      ? parseInt(minPriceInput.value) 
      : 0; // 未入力時は0
    const maxPrice = maxPriceInput.value !== ''
      ? parseInt(maxPriceInput.value)
      : Number.MAX_SAFE_INTEGER; // 未入力時は最大値

    // スペック範囲の処理
    const minSpecInput = document.getElementById('minSpec');
    const maxSpecInput = document.getElementById('maxSpec');
    const minSpec = minSpecInput.value !== ''
      ? parseInt(minSpecInput.value)
      : 0; // 未入力時は0
    const maxSpec = maxSpecInput.value !== ''
      ? parseInt(maxSpecInput.value)
      : Number.MAX_SAFE_INTEGER; // 未入力時は最大値

    return data.filter(item => 
      item.price >= minPrice &&
      item.price <= maxPrice &&
      item.spec >= minSpec &&
      item.spec <= maxSpec
    );
  };

  
// 初期化処理
window.addEventListener('DOMContentLoaded', () => {
    initializeData();
    updateDisplay();
  });
  </script>
</body>
</html>

Discussion