--- tags: JS 5組 - 2022 秋季 JS直播班, 最終關卡挑戰 Day1 - 前台(取得產品、購物車列表) title: 最終關卡挑戰 Day1 - 前台(取得產品、購物車列表) --- ###### tags: `JS 5組 - 2022 秋季 JS直播班` 、`最終關卡挑戰 Day1 - 前台(取得產品、購物車列表)` ###### *date: 2022 / 11/ 21* # Day 1 - 前台(取得產品、購物車列表) ### 今日挑戰目標: 前台(取得產品、購物車列表) ![](https://i.imgur.com/G7uv7oC.png) ### 使用到 API ![](https://i.imgur.com/AfvGim2.png) ### 六角學院 - [最終關卡資源](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'); }) }) ```