---
tags: JS 5組 - 2022 秋季 JS直播班, 最終關卡挑戰 Day1 - 前台(取得產品、購物車列表)
title: 最終關卡挑戰 Day1 - 前台(取得產品、購物車列表)
---
###### tags: `JS 5組 - 2022 秋季 JS直播班` 、`最終關卡挑戰 Day1 - 前台(取得產品、購物車列表)`
###### *date: 2022 / 11/ 21*
# Day 1 - 前台(取得產品、購物車列表)
### 今日挑戰目標: 前台(取得產品、購物車列表)

### 使用到 API

### 六角學院 - [最終關卡資源](https://www.notion.so/API-8b5b74eb052b451faf28013d76811fac)
### 攻克最終關卡前準備:
1. [前台版型](https://codepen.io/hexschool/pen/ExLbePp?editors=1010)
2. 申請[API](https://livejs-api.hexschool.io/)並[測試](https://hexschool.github.io/hexschoolliveswagger/)是否能成功接取資料
3. 認識[HTTP 回傳狀態碼](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status)
4. HTTP method
- GET:**取得內容** (今天要使用 get 取得產品、購物車列表)
- PUT:**替換內容**
- PATCH:**替換部分內容**
- DELETE:**刪除內容**
- POST:**新增內容**
5. axios(https://github.com/axios/axios) 套件安裝
```jsx
<script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js">
</script>
```
---
### shinyhung#3825
> 最終任務解題分享
* [設計稿](https://xd.adobe.com/view/a48b8617-4588-4817-9062-b62130dce916-f1d8/)
* [前台版型](https://codepen.io/hexschool/pen/ExLbePp?editors=1010)
* [後台版型](https://codepen.io/hexschool/pen/WNJXgrR?editors=1010)
* [API文件](https://hexschool.github.io/hexschoolliveswagger/)
---
### 參考老師的開發流程
:::spoiler 待辦事項
- [x] 環境建立
- [x] 建立環境架構(NPM管理、使用JS框架、手刻等)
- [x] 載入套件資源(boostrap、axios、cs.js sweetAlert..)
- [x] 建立CSS、JS架構(如靜態檔案、JS資源、SCSS檔案..)
- [x] API config設定(整合API串接檔案)
- [ ] 前台開發
- [ ] 產品 API 設計
- [x] 購物車 API 設計
- [ ] 產生訂單 API 設計
- [ ] 後台開發
- [ ] 訂單列表設計
- [ ] C3.js 圖表設計
- [ ] 優化細節
- [ ] 使用者操作體驗
- [ ] 千分位設計
- [ ] 驗證表單優化
- [ ] C3.js 圖表資料格式
- [ ] RWD優化
- [ ] 增加視覺互動效果
- [ ] 加入登入註冊功能
:::
---
* 環境建立
1. 建立專案資料夾
2. 載入Google字型、icon資源
3. 分析前後台版型資料結構
```javascript
```
### WeiJ#7376
> 確認 API 文件內容及撰寫相關 JS
通常在實作接別人 API 服務時我會優先讀完整份文件,並撰寫統一的 js 做管理
* 好處一 : 是若 API 有問題能夠即時與對方反應
* 好處二 : 將 API 統一管理如果有多支檔案使用同一個 API 只需要改一個檔案
這邊有兩個情形,分別為需要及不需要 Token,可以使用 axios 內建功能
`axios.create()` 來做 API 程式的初始化
```javascript
// api.js
const userRequest = axios.create({
baseURL: 'https://livejs-api.hexschool.io/api/livejs/v1/customer/weij0/',
headers: {
'Content-Type': 'application/json',
}
})
const adminRequest = axios.create({
baseURL: 'https://livejs-api.hexschool.io/api/livejs/v1/admin/weij0/',
headers: {
'Content-Type': 'application/json',
'Authorization': token,
}
})
```
如果是不需要 Token 我就直接使用 `userRequest` 來接參數,這邊會帶入API路徑網址,像是 `/products`, 因為有初始化所以前方會補上宣告的 `baseURL`
```javascript
export const apiGetProduct = () => userRequest.get('/products');
```
箭頭涵式直接回傳初始化的 axios Promise 所以程式端只要用 `.then()` 接上
```javascript
// index.js
import * as api from "./helper/api.js";
api.apiGetProduct().then(res => res.data.data)
```
### charlottelee849#0366
待辦事項
- 前台
- [ ] 取得產品列表
- [x] 取得購物車列表
- [x] 新增購物車品項
- [x] 初始化購物車列表
- [x] 初始化產品列表
- [x] 加入購物車
- [x] 刪除單筆購物車
- [x] 刪除整筆購物車
- [x] 送出購買訂單
- [ ] 表單驗證
- [ ] 千分位
- 後台
- [ ] 觀看後台訂單
**前台知識點**
將重覆用到的單一產品 html 碼寫成一個函式
```JavaScript
// 消除重複
function strChange(item) {
return `<li class="productCard">
<h4 class="productType">新品</h4>
<img
src="${item.images}"
alt="">
<a href="#" class="js-addCart" data-id="${item.id}">加入購物車</a>
<h3>${item.title}</h3>
<del class="originPrice">NT$${item.origin_price}</del>
<p class="nowPrice">NT$${item.price}</p>
</li>`;
}
```
再將消除重覆函式 strChange() 放入 productSelect 監聽函式重覆利用
```JavaScript=
productSelect.addEventListener("change", (e) => {
const category = e.target.value;
if (category == "全部") {
renderProductList();
return;
}
// 組字串 + 消除重複
let str = "";
productData.forEach((item) => {
if (item.category == category) {
str += strChange(item);
}
});
productList.innerHTML = str;
});
```
### jimmyFang#9575
**任務清單(完成)**:
- 產品
- [x] 取得產品資料
- [x] 顯示產品列表
- [x] 篩選產品種類
- 購物車
- [x] 取得購物車資料
- [x] 顯示購物車列表
- 工具
- [x] 千分位
- [x] 計算金額
**程式碼:** [codepen](https://codepen.io/pohxiqqo/pen/jOKYXLv)
**知識點分享:**
因為上次有看到 charlottelee 使用遠端資料內的類別去動態顯示下拉選單的 **option**,所以這次也練習不要寫死選單的**option**,以下為自己練習程式碼片段。
```jsx=
// 產品 - 顯示 select 下拉選單選項
function renderProductsOption(data) {
// 去除重複類別
const options = Array.from(new Set(data.map((product) => product.category)));
// 組下拉選項字串
let optionsList = `<option value="全部" selected>全部</option>`;
options.forEach((option) => {
optionsList += `<option value="${option}">${option}</option>`
});
productSelect.innerHTML = optionsList;
};
```
### Judy Wei#6103
```JavaScript
```
### Mia小福#4473
- 任務清單
- [x] 環境建立
- [ ] 取得產品列表
```JavaScript
先跟著老師的影片做一遍中~ 全部完成後會再用自己的邏輯試著做一次
```
### Ringo#7583
```JavaScript
```
### yawun#0042
- 任務清單(已完成)
- 產品
- [x] 取得產品資料
- [x] 顯示產品列表
- [x] 篩選產品種類
- 購物車
- [x] 取得購物車資料
- [x] 顯示購物車列表
- 優化工具
- [x] 千分位
- 待完成: 蒐集大家的寫法,持續優化(e.g. jimmy的選單渲染、weij的模組(待釐清))
- 知識點分享(大部分都按照老師的demo沒什麼特別的><)
- 在取得購物車資料時將購物車內容和總額分別取出,作為渲染的函式參數
```JavaScript=
//取得購物車清單
function getCartList(){
axios.get(`${baseUrl}/api/livejs/v1/customer/${api_path}/carts`)
.then(function (response) {
cartData = response.data.carts;//取出購物車資料
const{finalTotal} = response.data;//取出購物車總額
renderCartList(cartData,finalTotal);//將上述兩個資料放入渲染函式
})
.catch((error)=>{
console.log(error.response.data);
})
}
//渲染購物車清單
function renderCartList(cartData,finalTotal){
const cartTotal = document.querySelector('[data-cart-total]');//總額的DOM
cartTotal.textContent = toThousands(finalTotal);//渲染總額
let str = '';
cartData.forEach((item)=>{
const {id:cartId,quantity} = item; //購物車id重新命名
const {title,price,images} = item.product;
str+=`<tr>
<td>
<div class="cardItem-title">
<img src="${images}" alt="">
<p>${title}</p>
</div>
</td>
<td>NT$${toThousands(price)}</td>
<td>${quantity}</td>
<td>NT$${toThousands(price*quantity)}</td>
<td class="discardBtn">
<a href="#" class="material-icons" data-cart-id="${cartId}">
clear
</a>
</td>
</tr>`
})
cartList.innerHTML = str;
}
```
### 法希娜#3206
完成:一般商品顯示,購物車顯示+正確總額
待完成:購物車單筆刪除/全部刪除/ 加入購物車
**本次新增知識點:
(一)抓取擁有同樣class但各自不同id的元素,求個別click事件的該id
```jsx=
const addCardBtn = document.querySelectorAll('.addCardBtn');
addCardBtn.forEach((btn,i) =>{
btn.addEventListener('click', (e) => {
const idVal = e.target.getAttribute('id');
})
})
```