---
# System prepended metadata

title: 飲料點餐版面（Vue挑戰版）
tags: [JS套件, HTML & CSS, 六角學院, JavaScript, 前端筆記, Vue]

---

# 飲料點餐版面（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)
---


#### ヽ(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)ﾉヽ(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人

##### 以上 如果註解哪裡有錯誤或有問題，歡迎提出來一起討論~~~~