# 飲料點餐版面(Vue挑戰版) ###### codepen在這邊:https://codepen.io/liu_0821/pen/rNrWYMP?editors=0010 ![](https://i.imgur.com/Be6hXMq.png) ## 前情提要 #### 額外增加的內容 ##### 1. 刪除單筆訂單 #### 這版之後打算再多增加幾項功能~~~~~ ##### 1. 可以修改訂單 ##### 2. 當訂單產生後,重新點選品項,訂單產生畫面即可隱藏起來 #### 一樣下方都有註解,直接看下方程式碼瞜 ## HTML ``` <div id="app"> <div class="container gx-2"> <div class="row gx-3 bg-light py-3"> <div class="col-md-4"> <div class="list-group"> <a href="#" class="list-group-item list-group-item-action" @click.prevent="selectedItem(item)" v-for="(item,key) in products" :key="item.name" :class="{'active':selectProduct.name === item.name}" > <h6 class="card-title mb-1">{{item.name}}</h6> <div class="d-flex align-items-center justify-content-between" > <p class="mb-0"><small>{{item.engName}}</small></p> <p class="mb-0"><small>NT$ {{item.price}}</small></p> </div> </a> </div> </div> <div class="col-md-8"> <div class="card mb-2"> <div v-if="!selectProduct.name " class="position-absolute text-white d-flex align-items-center justify-content-center" style=" top: 0; bottom: 0; left: 0; right: 0; background-color: rgba(0, 0, 0, 0.65); z-index: 100; " > 請先選擇飲品 </div> <div class="card-body px-4"> <div class="mb-3"> <label for="productNum" class="form-label">數量</label> <input type="number" class="form-control" id="productNum" placeholder="數量" min="1" v-model="selectProduct.count" /> </div> <div class="mb-3"> <label for="productNum" class="form-label d-block" >冰塊*</label > <div class="form-check form-check-inline" v-for="(item,key) in iceType" :key="'ice'+ key" > <input class="form-check-input" name="iceType" type="radio" :value="item" :id="'ice'+ key" v-model="selectProduct.ice" :disabled="!selectProduct.hasOwnProperty('defaults') || (selectProduct.defaults.ice !== '' && selectProduct.defaults.ice !== item)" /> <!--hasOwnProperty 測試屬性是否存在--> <label class="form-check-label" :for="'ice'+ key" >{{item}}</label > </div> </div> <div class="mb-3"> <label for="productNum" class="form-label d-block" >甜度*</label > <div class="form-check form-check-inline" v-for="(item,key) in sugarType" :key="'sugar'+ key" > <input class="form-check-input" name="sugarType" type="radio" :id="'sugar'+ key" :value="item" v-model="selectProduct.sugar" :disabled="!selectProduct.hasOwnProperty('defaults') || (selectProduct.defaults.sugar !== '' && selectProduct.defaults.sugar !== item)" /> <label class="form-check-label" :for="'sugar'+ key" >{{item}}</label > </div> </div> <div class="mb-3"> <label for="productNum" class="form-label d-block" >加料</label > <div class="form-check form-check-inline" v-for="(item,key) in toppingsType" :key="'topping'+key" > <input class="form-check-input" type="checkbox" :id="'topping'+key" :value="item" v-model="selectProduct.topping" :disabled="!selectProduct.hasOwnProperty('defaults') || selectProduct.defaults.toppings.includes(item)" /> <label class="form-check-label" :for="'topping'+key" >{{item}}</label > </div> </div> <div class="mb-3"> <label for="productNotice" class="form-label" >備註</label > <textarea class="form-control" id="productNotice" rows="2" v-model="selectProduct.text" ></textarea> </div> <div class="d-flex gap-2"> <button class="btn btn-outline-primary w-100" type="button" > 取消 </button> <button class="btn btn-primary w-100" @click.prevent="addToShoppingCart(selectProduct)" type="button" > 加入 </button> </div> </div> </div> <div class="card"> <div class="card-body"> <table class="table"> <thead> <tr> <th scope="col">品項</th> <th scope="col">冰塊</th> <th scope="col">甜度</th> <th scope="col">加料</th> <th scope="col">單價</th> <th scope="col">數量</th> <th scope="col">小計</th> <th scope="col"></th> </tr> </thead> <tbody> <tr v-for="(item,key) in orderList" :key="'key'+key"> <th scope="row"> {{item.name}}<br /> <small class="text-muted fw-normal" >備註:{{item.text}}</small > </th> <td>{{item.ice}}</td> <td>{{item.sugar}}</td> <td>{{item.topping.toString()}}</td> <td>{{item.price + item.topping.length*10}}</td> <td>{{item.count}}</td> <td>{{item.total}}</td> <td class="text-end" @click.prevent="deleteOrder(item)" > <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16" > <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" /> </svg> </td> </tr> </tbody> </table> <p class="text-end">共 NT$ {{totalPrice}} 元</p> <div class="d-flex gap-2"> <button class="btn btn-sm btn-outline-secondary w-100" @click.prevent="clearOrder" > 清空購物車 </button> <button class="btn btn-sm btn-secondary w-100" @click.prevent="outputOrder(orderList,totalPrice)" :disabled="orderList.length === 0" > 產生訂單 </button> </div> </div> </div> </div> </div> </div> <div class="bg-light p-3 mt-3" v-if="checkedOrder.orders.length >0 " > <div class="bg-white p-3 d-flex flex-column" style="min-height: 450px" > <table class="table"> <thead> <tr> <th scope="col">品項</th> <th scope="col">冰塊</th> <th scope="col">甜度</th> <th scope="col">加料</th> <th scope="col">單價</th> <th scope="col">數量</th> <th scope="col">小計</th> </tr> </thead> <tbody> <tr v-for="(item,id) in checkedOrder.orders" :key="'id'+id"> <th scope="row"> {{item.name}}<br /> <small class="text-muted fw-normal" >備註:{{item.text}}</small > </th> <td>{{item.ice}}</td> <td>{{item.sugar}}</td> <td>{{item.topping.toString()}}</td> <td>{{item.price + item.topping.length*10}}</td> <td>{{item.count}}</td> <td class="text-end">{{item.total}}</td> </tr> </tbody> </table> <p class="mt-3 mb-1">訂單成立時間:{{checkedOrder.date}}</p> <p class="mb-1">餐點數: {{checkedOrder.orderCount}}</p> <p class="mb-1">付款狀態:未付款</p> <p class="text-end mt-auto"> 共 NT$ {{checkedOrder.checkOrderPrice}} 元 </p> </div> </div> </div> ``` ## JS(Vue) > `selectProduct` 放被選擇的項目 `orderList` 購物車 `totalPrice` 總價 `checkedOrder` 結帳 ``` const App = { data() { return { selectProduct: {}, orderList: [], checkedOrder: { orders: [], date: "", orderCount: 1, checkOrderPrice: "", }, iceType: ["正常冰", "少冰", "微冰", "去冰", "熱"], sugarType: ["全糖", "七分", "半糖", "三分", "無糖"], toppingsType: ["珍珠", "粉條", "小粉圓", "椰果", "芋頭"], products: [ { name: "珍珠鮮奶茶", engName: "Pearl Milk Tea", price: 60, defaults: { toppings: ["珍珠"], sugar: "", ice: "", }, }, { name: "椰果鮮奶茶", engName: "Coconut Milk Tea", price: 60, defaults: { toppings: ["椰果"], sugar: "", ice: "", }, }, { name: "鮮奶茶", engName: "Milk Tea", price: 50, defaults: { toppings: [""], sugar: "", ice: "", }, }, { name: "古意冬瓜茶 (糖固定)", engName: "Winter Melon Drink", price: 30, defaults: { toppings: [""], sugar: "全糖", ice: "", }, }, { name: "蜜香紅茶", engName: "Black Tea", price: 30, defaults: { toppings: [""], sugar: "", ice: "", }, }, { name: "包種青茶", engName: "Black Tea", price: 35, defaults: { toppings: [""], sugar: "", ice: "", }, }, { name: "檸檬烏龍", engName: "Lemon Oolong Tea", price: 55, defaults: { toppings: [""], sugar: "", ice: "", }, }, { name: "薑母茶 (熱飲)", engName: "Ginger Tea", price: 55, defaults: { toppings: [""], sugar: "", ice: "熱", }, }, { name: "青草茶", engName: "Herbal Tea", price: 35, defaults: { toppings: [""], sugar: "", ice: "", }, }, { name: "金桔檸檬", engName: "Kumquat Lemonade", price: 40, defaults: { toppings: [""], sugar: "", ice: "", }, }, { name: "柳澄青茶", engName: "Orange Mountain Tea", price: 45, defaults: { toppings: [""], sugar: "", ice: "", }, }, ], }; }, methods: { selectedItem(product) { this.selectProduct = { ...product, count: 1, ice: product.defaults.ice !== "" ? product.defaults.ice : "正常冰", sugar: product.defaults.sugar !== "" ? product.defaults.sugar : "全糖", text: "", // 備註 topping: [], // 加料 }; }, addToShoppingCart(selectProduct) { const order = { ...selectProduct, total: (selectProduct.price + selectProduct.topping.length * 10) * selectProduct.count, }; this.orderList.push(order); this.resetOrder(); // 加入購物車後清空 this.countTotal(); // 計算總價 }, countTotal() { this.totalPrice = 0; this.orderList.forEach((item) => { this.totalPrice += item.total; }); }, clearOrder() { this.totalPrice = 0; this.orderList.length = 0; // 也可以這樣寫 this.orderList = []; }, outputOrder(orders, total) { const date = new Date().toLocaleString(); // 訂單時間 const orderCount = orders.length; this.checkedOrder.date = date; this.checkedOrder.orders = orders; this.checkedOrder.orderCount = orderCount; this.checkedOrder.checkOrderPrice = total; this.orderList = []; this.resetOrder(); }, resetOrder() { this.selectProduct = {}; }, deleteOrder(item) { this.orderList.splice(this.orderList.indexOf(item), 1); }, }, }; Vue.createApp(App).mount("#app"); ``` ## 後續補充 #### 耶補充一下新增的功能 / 修改的部分 #### 一、點選品項會把下方的訂單區塊隱藏起來 ##### 在點選品項時,觸發`selectedItem`去清除目前訂單的資料`this.checkedOrder.orders.length = 0`,如此一來`v-if`的判斷式就會觸發~~ #### 二、修改個別訂單資料 ##### 目前還是先用比較簡單的版本哈,在前面[選我](https://hackmd.io/@LindaLiu/HkPXfG-cs)也有提到的方式來做修改訂單的部分~ #### 更新版本會另外放一篇筆記做個紀錄~~~ #### [更新版本在這裡~](https://hackmd.io/@LindaLiu/Hyb8hlrqi) --- #### ヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人 ##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~