Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

[Express+Vue 搭建電商網站] 20 重構後的頁面功能恢復

使用 Express + Vue 搭建一個電商網站 - 重構後的頁面功能恢復

Ray

要是你跟老闆說:現在我們專案的畫面好看了,但是功能全壞了
老闆應該會一臉問號問你在講什麼?
廢話不多說,趕快來修好上一篇中被我們弄壞的功能!

修復雙向綁定的問題

上一篇中有提過 element-ui 的輸入組件不接受 v-model 的功能
所以為了雙向綁定資料,我們需要利用其他方法

Edit 組件

首先打開 Edit 組件進行修復

<template>
  <div>
    <div class="title">
      <h1>This is Admin/Edit</h1>
    </div>
    <product-form
      @save-product="updateProduct"
      :model="model"
      :manufacturers="manufacturers"
      :isEditing="true"
    ></product-form>
  </div>
</template>

<script>
import ProductForm from "@/components/products/ProductForm.vue";
export default {
  created() {
    const { name = "" } = this.modelData || {};

    if (!name) {
      this.$store.dispatch("productById", {
        productId: this.$route.params["id"]
      });
    }

    if (this.manufacturers.length === 0) {
      this.$store.dispatch("allManufacturers");
    }
  },
  computed: {
    manufacturers() {
      return this.$store.getters.allManufacturers;
    },
    model() {
      const product = this.$store.getters.productById(this.$route.params["id"]);
      const res = { ...product, manufacturer: { ...product.manufacturer } };

      return res;
    }
  },
  methods: {
    updateProduct(product) {
      this.$store.dispatch("updateProduct", {
        product
      });
    }
  },
  components: {
    "product-form": ProductForm
  }
};
</script>

這一步中我們又將 data 屬性中的 model 給恢復到了 computed 中,用來暫存 model 物件的資料提高效能
而雙向綁定的問題會在其中的 ProductForm 解決

ProductForm 組件

我們來嘗試另一種方式修復雙向綁定,先看程式碼

<template>
  <div class="productInfo">
    <el-form class="form" ref="form" label-width="180px">
      <el-form-item label="Name">
        <el-input v-model="modelData.name"></el-input>
      </el-form-item>
      <el-form-item label="Price">
        <el-input v-model="modelData.price"></el-input>
      </el-form-item>
      <el-form-item label="Manufacturer ">
        <el-select v-model="modelData.manufacturer.name" clearable placeholder="請選擇製造商">
          <el-option
            v-for="manufacturer in manufacturers"
            :key="manufacturer._id"
            :label="manufacturer.name"
            :value="manufacturer.name"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="Image ">
        <el-input v-model="modelData.image"></el-input>
      </el-form-item>
      <el-form-item label="Description ">
        <el-input type="textarea" v-model="modelData.description"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button v-if="isEditing" type="primary" @click="onSubmit">Update Product</el-button>
        <el-button v-else @click="onSubmit">Add Product</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      modelData: { manufacturer: { name: "" } }
    };
  },
  props: ["model", "manufacturers", "isEditing"],
  created() {
    const product = this.model;
    this.modelData = { ...product, manufacturer: { ...product.manufacturer } };
  },
  watch: {
    model(val) {
      this.modelData = val;
    }
  },
  methods: {
    onSubmit() {
      const manufacturer = this.manufacturers.find(
        item => item.name === this.modelData.manufacturer.name
      );
      this.modelData.manufacturer = manufacturer;
      this.$emit("save-product", this.modelData);
    }
  }
};
</script>

<style>
.productInfo {
  padding-top: 10px;
}
.form {
  margin: 0 auto;
  width: 500px;
}
.el-input__inner {
  height: 60px;
}
</style>

在上面的程式中,不直接使用父組件的 model 作為表單的資料物件
而是在目前的組件中自訂一個新的 modelData 物件
並且在組件剛被建立時就先從父組件取得 modle 物件,暫定為 product
然後將 product 需要用到的屬性解構給 modelData 物件

這樣就避免了表單物件操作 computed,但這只解決了一半問題,說好的雙向綁定呢?
所以我們要透過監測組件的變化,利用 watch 方法監測使用者輸入
並且將新的資料儲存到 modelData 物件中,這樣就完成雙向綁定啦!而且表單也可以隨意編輯

商品資訊表單錯誤問題

當修改或是新建表單時,會看到錯誤的提示訊息:id 屬性未定義
因為錯誤訊息說是在 ProductForm 中,就來看看發生什麼事情了吧

應該都還記得,商品的物件的製造商包含了 idname 屬性
但是我們的下拉選單的 value 只有傳回 name
而後端資料庫要求製造商物件必須也要有 id 屬性
所以在送出時使用了 find 方法找到了對應 name 的製造商物件
並且將 modelData 中的製造商物件覆蓋掉,這樣就符合後端資料庫的要求了!


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

最新文章

Category

Tag