---
# System prepended metadata

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

---

# 飲料點餐版面（Vue最終進階版）
###### codepen在這邊：https://codepen.io/liu_0821/pen/GRBrwzW?editors=0011
![](https://i.imgur.com/YuIE3eA.jpg)


## 前情提要
###### 前面的版本在這邊~~ [**版本1**](https://hackmd.io/@LindaLiu/HkTU3gSqi)   [**版本2**](https://hackmd.io/@LindaLiu/ryBeOxt9i) 
##### 修修改改終於來到最後一版，目前增加的內容一定會有更好的寫法（Computed），但未來的路還很長，想說目前先改這樣，等後續再來做修改d(`･∀･)b

#### 額外增加的內容
##### 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>
                  <th scope="col"></th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(item,key) in orderList" :key="'data'+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.calculatePrice}}</td>
                  <td>{{item.count}}</td>
                  <td>{{item.calculatePrice*item.count}}</td>
                  <td class="text-end">
                    <svg
                         xmlns="http://www.w3.org/2000/svg"
                         width="16"
                         height="16"
                         fill="currentColor"
                         class="bi bi-pencil-square editIcon"
                         viewBox="0 0 16 16"
                         @click.prevent="editOrder(item)"
                         >
                      <path
                            d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"
                            />
                      <path
                            fill-rule="evenodd"
                            d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"
                            />
                    </svg>
                  </td>
                  <td class="text-end">
                    <svg
                         xmlns="http://www.w3.org/2000/svg"
                         width="16"
                         height="16"
                         fill="currentColor"
                         class="bi bi-x delIcon"
                         viewBox="0 0 16 16"
                         @click.prevent="deleteOrder(item)"
                         >
                      <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.calculatePrice}}</td>
            <td>{{item.count}}</td>
            <td class="text-end">{{item.calculatePrice*item.count}}</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` 結帳
              `calculatePrice` 計算金額

**data的部分**
```
// 在原本的資料結構上有更動 
selectProduct: {
        id: "", -> 判斷修改還是新增的依據
        calculatePrice:0,  -> 計算小計
      },
      orderList: [],
      checkedOrder: {
        orders: [],
        date: "",
        orderCount: 1,
        checkOrderPrice: "",
        }
```
**計算價格**
```
addToShoppingCart(selectProduct) {
        /* 把小計的部份另外拉出來算 */    
      this.selectProduct.calculatePrice = 
      this.selectProduct.price + this.selectProduct.topping.length * 10; 
      if (!this.selectProduct.id) {
        this.selectProduct.id = new Date().getTime();
        const order = {
          ...selectProduct,
          total:0  -> 預設
        };
        this.orderList.push(order);
      } else {
        this.orderList.map((item, i) => {
          if (item.id === this.selectProduct.id) {
            
            this.orderList[i] = this.selectProduct;
          }
        });
      }
      this.countTotal();
      this.resetOrder(); // 加入購物車後清空
    }
```
```
countTotal() {
      this.totalPrice = 0;
      this.orderList.forEach((item) => {
        // 計算整筆訂單的總價格(暴力拆解?)
        this.totalPrice += (item.price + item.topping.length*10)*item.count;
      });
    },
```

## 後續補充
##### 有發現一些小問題有在做重新調整，以及有一些建議把它紀錄下來
* ##### 更新訂單`outputOrder()`時建議如下的寫法，除了更為精簡，其次是創造一筆全新的資料保持資料不變 (immutable) (這就比較偏架構程式的方法，並沒有對錯)。

##### 補充資料：
##### [前端的 immutable 設計樣式](https://blog.yyisyou.tw/c30df041/)

---


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

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