<div class="wrap">
  <div class="main rounded">
     <h2 class="text-center mb-4">蔬菜比價網</h2>
    <div class="button-group d-flex justify-content-center mb-4">
<!--       埋藏 data-type 的 DOM -->
      <button  type="button" class="allBtn btn btn-type border-dark border-2">全部</button>
      <button data-type="N04" type="button" class="vegetablesBtn btn btn-type border-dark border-2">蔬果</button>
      <button data-type="N05" type="button" class="fruitsBtn btn btn-type border-dark border-2">水果</button>
      <button data-type="N06" type="button" class="flowersBtn btn btn-type border-dark border-2">花卉</button>
    </div>
    <div class="search-group d-flex flex-md-row flex-column align-items-center">
      <div class="crop-input d-flex mb-2 ">
        <label class="rounded-start text-white" for="crop">作物名稱</label>
        <input class="rounded-end" type="search" placeholder="請輸入作物名稱" id="crop" name="crop">
      </div>
      <button type="button" class="search text-white btn mb-2">搜尋</button>
    </div>
    <select id="js-select" class="sort-select border-secondary rounded mb-3 p-2 pe-4">
      <option>排序篩選</option>
      <option>依上價排序</option>
      <option>依中價排序</option>
      <option>依下價排序</option>
      <option>依平均價排序</option>
      <option>依交易量排序</option>
    </select>
    <table class="market table me-4">
      <thead class="js-sort-advanced">
        <tr>
          <th width="16.6%">作物名稱</th>
          <th width="16.6%">上價
              <span>
                <i data-price="上價" data-sort="up" class="fas fa-caret-up"></i>
                <i data-price="上價" data-sort="down" class="fas fa-caret-down"></i>
              </span>
          </th>
          <th width="16.6%">中價
              <span>
                <i data-price="中價" data-sort="up" class="fas fa-caret-up"></i>
                <i data-price="中價" data-sort="down" class="fas fa-caret-down"></i>
              </span>
          </th>
          <th width="16.6%">下價
            <span>
                <i data-price="下價" data-sort="up" class="fas fa-caret-up"></i>
                <i data-price="下價" data-sort="down" class="fas fa-caret-down"></i>
              </span>
          </th>
          <th width="16.6%">平均價
            <span>
                <i data-price="平均價" data-sort="up" class="fas fa-caret-up"></i>
                <i data-price="平均價" data-sort="down" class="fas fa-caret-down"></i>
              </span>
          </th>
          <th width="16.6%">交易量
            <span>
                <i data-price="交易量" data-sort="up" class="fas fa-caret-up"></i>
                <i data-price="交易量" data-sort="down" class="fas fa-caret-down"></i>
              </span>
          </th>
        </tr>
      </thead>
      <tbody class="showList">
        <tr>
          <td colspan="6" class="text-center p-3">請輸入並搜尋想比價的作物名稱^_^</td>
        </tr>
      </tbody>
    </table>

  </div>
</div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
*,
*::before,
*::after {
  box-sizing: border-box;
}

img {
  max-width: 100%;
  height: auto;
}
body {
  background: url(https://hexschool.github.io/js-filter/assets/bg.jpg);
  background-size: cover;
  height: 100vh;
  font-family: "NotoSansCJKtc-Bold";
  color: #2a2a2a;
  letter-spacing: 1px;
  white-space: nowrap;
}
.wrap {
  max-width: 1140px;
  margin: 1rem auto;
}

.main {
  background: #fff;
  border: 5px solid #fff8d45a;
  padding: 2.5rem;
}
@media (max-width: 767px) {
  .main {
    padding: 0.75rem;
  }
}
.btn-type {
  padding: 0.5rem 2.5rem;
  color: #2a2a2a;
  letter-spacing: 1px;
  margin: 0 0.625rem 1.25rem 0;
}

.btn-type:hover,
.btn-type:active {
  background: #f8d45a;
}
@media (max-width: 767px) {
  .btn-type {
    padding: 0.5rem 2.25rem;
    margin: 0 0.375rem 1rem 0;
  }
}
.active{
  background: #f8d45a;
}
.seach-group {
  white-space: nowrap;
  display: flex;
  align-items: center;
  margin-bottom: 2.5rem;
  width: 100%;
}

.crop-input {
  width: 60%;
  margin: auto;
}

.crop-input label {
  background: #899e39;
  display: flex;
  align-items: center;
  padding: 0.5rem 1rem;
  width: 27.5%;
}

.crop-input input {
  width: 80%;
  border: 2px #899e39 solid;
  padding: 0.375rem;
  margin-left: -0.3125rem;
  margin-right: 1rem;
}



.search {
  width: 40%;
  background: #899e39;
  padding: 0.5rem 3.375rem;
}
@media (max-width: 767px) {
  .seach-group {
    margin-bottom: 1.5rem;
  }
  .crop-input {
    width: 100%;
  }
  .search {
    width: 100%;
  }
}
.market thead {
  background: #f4f1ea;
  border-top: 2px solid #2a2a2a;
  border-bottom: 2px solid #2a2a2a;
}
.market tbody {
  border-bottom: 2px solid #d9d9d9;
}
@media (max-width: 480px) {
  table {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
  }
}


.sort-select {
  appearance: none;
  -moz-appearance: none;
  -webkit-appearance: none;
  background: url('data:image/svg+xml;utf8,<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sort-down" class="svg-inline--fa fa-sort-down fa-w-2" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="10 0 320 900"><path fill="currentColor" d="M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z"></path></svg>')
    no-repeat;
  background-position: 105px 5px;
}

.sort-content {
  margin-bottom: 1.25rem;
}
// JSON 檔案網址
const url = "https://shannon945.github.io/farm_produce/data.json";
const productsList = document.querySelector(".showList");
let data = [];

/** 步驟一 取得資料**/
function getData(){
  axios.get(url)
    .then(function(response){
      // 檢查: 
    console.log(response.data);
      // 將取得資料帶入空陣列 data 中
      data = response.data;
    
      // 執行渲染 (請留意非同步)
      renderData(data);
  })
}
getData();


 /** 步驟二 渲染**/
function renderData(arr) {
  // 宣告空字串,可存入資料
  let str = "";
  
  //請透過 data 陣列跑 forEach ,並至少帶入第一個參數
  arr.forEach(function(item){
      str +=`
        <tr>
          <td>${item.作物名稱}</td>
          <td>${item.上價}</td>
          <td>${item.中價}</td>
          <td>${item.下價}</td>
          <td>${item.平均價}</td>
          <td>${item.交易量}</td>
        </tr>`
    })
  // 檢查:console.log(str);
  productsList.innerHTML = str;
}

 /** 步驟三 點擊到該按鈕時,按鈕能維持變色!**/
const btnGroup = document.querySelector('.button-group');

// 監聽蔬果、水果、花卉按鈕
btnGroup.addEventListener('click', (e)=>{
  // 重新渲染的陣列內容
  let update = [];

  //點擊後,先全部清除 active,然後再添加 active
  const tabs = document.querySelectorAll(".button-group button");
  
  // 因為監聽的 btnGroup 範圍有包 div,所以要確保只點到 button 才會換色
  if(e.target.nodeName === "BUTTON"){
    tabs.forEach((item)=>{
      return item.classList.remove('active')
    });

    // filter 篩選蔬果、水果、花卉
    // 使用 .classList.contains 找到其中一個 class
    // 或使用 dataset
    if(e.target.classList.contains('vegetablesBtn')){
      // 蔬果 "種類代碼": type="N04"
       update = data.filter((item)=> item.種類代碼 === 'N04')
       }else if(e.target.dataset.type === 'N05'){
      // 水果 "種類代碼": type="N05"
       update = data.filter((item)=> item.種類代碼 === 'N05')
       }else if(e.target.dataset.type === 'N06'){
      // 花卉 "種類代碼": type="N05"
       update = data.filter((item)=> item.種類代碼 === 'N06')
       }else if(e.target.classList.contains('allBtn')){
      // 蔬果 "種類代碼": type="N04"
       update = data;
       }


    e.target.classList.add('active');
    renderData(update);
  }
})


/** 搜尋 **/
const searchBtn = document.querySelector('.search')

searchBtn.addEventListener('click', (e)=>{
  const searchInput = document.querySelector('.rounded-end');
  
  // 篩選 data 賦予到一個空陣列上
  let filterData = [];
  
  // 如果輸入框為空值,會提醒
  if(searchInput.value === ""){
    alert('請輸入作物名稱')
  } else {
    filterData = data.filter((item)=> {
      // 回傳 .match 符合的匹配結果
      // data 中的作物名稱與搜尋框中的 value 相互 match 篩選的內容,並回傳空陣列
      return item.作物名稱.match(searchInput.value);
    })
    
    // 如果 filterData 篩選出來仍為空陣列,回傳無此作物名稱
    if(filterData.length === 0){
      productsList.innerHTML = `<tr>
          <td colspan="6" class="text-center p-3">查無此作物名稱^_^</td>
        </tr>`
    } else {
       renderData(filterData);
    }
  }
})


/** 排序篩選 **/
const jsSelect = document.getElementById('js-select');

// 點擊選單,利用 switch 選取篩選特定內容 + .sort() 排序資料
jsSelect.addEventListener('change', (e)=>{
  switch(e.target.value){
    case '依上價排序':
      selectSort('上價');
      break;
    case '依中價排序':
      selectSort('中價');
      break;
    case '依下價排序':
      selectSort('下價');
      break;
    case '依平均價排序':
      selectSort('平均價');
      break;
    case '依交易量排序':
      selectSort('交易量');
      break;
    default:
  }
})

function selectSort(value){
  data.sort((a, b)=> {
   return a[value] -  b[value]; 
  })
  renderData(data);
}

/** 進階排序(上下箭頭) **/
const sortAdvanced = document.querySelector('.js-sort-advanced');
sortAdvanced.addEventListener('click', (e)=>{
  if (e.target.dataset.sort === 'up'){
    data.sort((a, b) => {
    // b - a 可實現從大排到小
      return b[e.target.dataset.price]-a[e.target.dataset.price]
    })
  }else {
    data.sort((a, b)=>{
      return a[e.target.dataset.price] - b[e.target.dataset.price]
    })
  }
  // 呼叫函式
  renderData(data);
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/c3.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/c3.js
  3. https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js