Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

[Express+Vue 搭建電商網站] 10 用 vue 建立一個表單

使用 Express + Vue 搭建一個電商網站 - 用 vue 建立一個表單

Ray

後端的 API 上次已經開了出來,接著來建立前端使用的表單
這次的目標是建立新增商品時所用的表單,會使用到基本的 Vue 知識,如果沒看過文件的可以先了解一下官方文件

架構規劃

之前我們建立了 /src/views/admin/New.vue 這個模板做為網址 /admin/new 的顯示頁面
在這節中會建立一個表單,然後讓他作為頁面組件顯示在 New.vue

程式實作

建立一個新的檔案 /src/components/products/ProductForm.vue 作為表單的組件
可以看到我們在這邊的存放位置不再是 /src/views/ 因為他是組件
好好的放在「components」內是比較好的架構方式

<template>
  <form @submit.prevent="saveProduct">
    <div class="col-lg-5 col-md-5 col-sm-12 col-xs-12">
      <div class="form-group">
        <label>Name</label>
        <input type="text" placeholder="Name" v-model="model.name" name="name" class="form-control" />
      </div>
      <div class="form-group">
        <label>Price</label>
        <input
          type="number"
          class="form-control"
          placeholder="Price"
          v-model="model.price"
          name="price"
        />
      </div>
      <div class="form-group">
        <label>Manufacturer</label>
        <select type="text" class="form-control" v-model="model.manufacturer" name="manufacturer">
          <template v-for="manufacturer in manufacturers">
            <option
              :key="manufacturer._id"
              :value="manufacturer._id"
              :selected="manufacturer._id == (model.manufacturer && model.manufacturer._id)"
            >{{manufacturer.name}}</option>
          </template>
        </select>
      </div>
    </div>

    <div class="col-lg-4 col-md-4 col-sm-12 col-xs-12">
      <div class="form-group">
        <label>Image</label>
        <input
          type="text"
          lass="form-control"
          placeholder="Image"
          v-model="model.image"
          name="image"
          class="form-control"
        />
      </div>
      <div class="form-group">
        <label>Description</label>
        <textarea
          class="form-control"
          placeholder="Description"
          rows="5"
          v-model="model.description"
          name="description"
        ></textarea>
      </div>
      <div class="form-group new-button">
        <button class="button">
          <i class="fa fa-pencil"></i>
          <!-- Conditional rendering for input text -->
          <span v-if="isEditing">Update Product</span>
          <span v-else>Add Product</span>
        </button>
      </div>
    </div>
  </form>
</template>

<script>
export default {
  props: ["model", "manufacturers", "isEditing"],
  methods: {
    saveProduct() {
      this.$emit("save-product", this.model);
    }
  }
};
</script>

程式說明

於是我們來看看這段看起來很長很嚇人的東西在做什麼?

分為兩部分來理解

script 部分

props 主要接收父組件傳來的三個參數 modelmanufacturersisEditing

然後在 methods 定義了一個方法 saveProduct,當使用者填完送出後按下送出會觸發這個方法
而在 saveProduct 內部調用了一個 save-product 方法,這個方法稍後會在父組件建立
除了調用父組件方法,在送出的同事還會把 this.model 內容傳遞給父組件

template 部分

淺而易見的 template 就是一個表單,其中的 submit 事件使用 @submit.prevent 禁用預設的送出行為
並使用 saveProduct 替換

接著寫了好幾個 class="form-group" 的區塊,代表要填寫的商品資料
其中前兩個區塊使用了 v-model 綁定 model 的 nameprice 兩個屬性
第三個區塊先對 select 標籤雙向綁定了 model.manufacturer 屬性
代表在內部做的行為都會影響對應的 model.manufacturer

接著使用迴圈把 script 中接收到的父組件 manufacturers 資料一個一個設為 option 標籤內容
並且把個別設定 manufacturer 的屬性
以及如果 model.manufacturer._id 和當前的 manufacturer._id 一致
就把 selected 屬性設為 true

接著第四個 form-group 開始,依然是使用 v-model 綁定 model.imagemodel.description 屬性
最後一個 form-group 使用 v-if 判斷式來判斷 isEditing 來渲染不同的按鈕文字


完成了子組件之後,就要引入父組件內。所以重新打開 New.vue 這個檔案,引入剛剛建立的表單組件

<template>
  <product-form
    @save-product="addProduct"
    :model="model"
    :manufacturers="manufacturers"
  >
  </product-form>
</template>

<script>
import ProductForm from '@/components/products/ProductForm.vue';
export default {
  data() {
    return {
      model: {},
      manufacturers: [
        {
          _id: 'sam',
          name: 'Samsung',
        },
        {
          _id: 'apple',
          name: 'Apple',
        },
      ],
    };
  },
  methods: {
    addProduct(model) {
      console.log('model', model);
    },
  },
  components: {
    'product-form': ProductForm
  }
}
</script>

當要在一個組件中使用另一個組件時,需要在父組件的 components 中註冊
在我們的 New.vue 中就將 ProductForm 註冊為 product-form
於是我們就可以在 <template> 區塊中使用 <product-form /> 來使用組件。

同時在 data 中定義了 modelmanufacturersmethods 中定義了 addProduct 方法
並且綁定成 @save-product="saveProduct" 事件傳遞給子組件使用

儲存之後,重新開啟前端網頁,進入新建商品的頁面就可以看到子組件已經被加入 New.vue 的畫面上
new-product-page

目前為止我們學會了

  • 使用 vue-router 進行多頁面的跳轉與路由
  • 使用嵌套路由有組織的管理前端路由
  • 基礎的 Vue 使用
  • 學會建立 Vue 的組件並在父組件中使用

專案範例程式碼 GitHub 網址:ray247k/mini-E-commerce

最新文章

Category

Tag