wordpress_blog

This is a dynamic to static website.

Vue3 複習02

快速入門 Vue.js: 商品後台管理介面

MVVM 概念介紹

Vue.js 起手式

環境安裝 – Vue.js devtools

// HTML
<div id="app">
  {{ counter }} 
  {{ text }}
</div>
// JS
Vue.createApp({
  data() {
    return {
      counter: 5,
      text: "這裡有一段文字",
    };
  },
}).mount("#app");

起手常見結構

// HTML
<div id="app">
  {{ counter }}
  <button type="button" v-on:click="clickMe">按我</button>
</div>
// JS
const app = {
  // 資料 (函式)
  data() {
    return {
      counter: 0,
    };
  },
  // 生命週期 (函式)
  created() {
    this.counter = 10;
    console.log(this);
  },
  // 方法 (物件)
  methods: {
    clickMe() {
      // console.log(1);
      this.counter = this.counter + 1;
    },
  },
};

Vue.createApp(app).mount("#app");

雙向綁定的技巧

// HTML
<div id="app">
  <form>
    {{ temp }}
    <div class="mb-3">
      <label for="productName" class="form-label">產品名稱</label>
      <input
        type="text"
        id="productName"
        class="form-control"
        v-model="temp.name"
      />
    </div>
    <div class="mb-3">
      <!-- HTML 屬性 -->
      <img v-bind:src="temp.imageUrl" class="img-fluid" alt="" />
      <label for="productImage" class="form-label">產品圖片</label>
      <input
        type="text"
        id="productImage"
        class="form-control"
        v-model="temp.imageUrl"
      />
    </div>
    <button type="button" class="btn btn-secondary" v-on:click="confirmEdit">
      更新
    </button>
  </form>
</div>
// JS
const App = {
  data() {
    return {
      temp: {
        name: "筆電",
        imageUrl:
          "https://images.unsplash.com/photo-1602526430780-782d6b1783fa?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
      },
    };
  },
  methods: {
    confirmEdit() {
      console.log(this.temp);
    },
  },
};

Vue.createApp(App).mount("#app");

將資料加入於 Vue Data

// HTML
<div id="app">
  <form>
    <div class="mb-3">
      <label for="productName" class="form-label">產品名稱</label>
      <input
        type="text"
        id="productName"
        class="form-control"
        v-model="temp.name"
      />
    </div>
    <div class="mb-3">
      <img :src="temp.imageUrl" class="img-fluid d-block" alt="" width="300" />
      <label for="productImage" class="form-label">產品圖片</label>
      <input
        type="text"
        id="productImage"
        class="form-control"
        v-model="temp.imageUrl"
      />
    </div>
    <button type="button" class="btn btn-secondary" v-on:click="confirmEdit">
      更新
    </button>
  </form>
</div>
// JS
const products = [
  {
    id: "1",
    imageUrl:
      "https://images.unsplash.com/photo-1516906571665-49af58989c4e?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=300&q=80",
    name: "MacBook Pro",
    onStock: false,
  },
  {
    id: "2",
    imageUrl:
      "https://images.unsplash.com/photo-1512499617640-c74ae3a79d37?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80",
    name: "iPhone",
    onStock: false,
  },
];
const App = {
  data() {
    return {
      temp: {
        name: "筆電",
        imageUrl:
          "https://images.unsplash.com/photo-1602526430780-782d6b1783fa?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
      },
      products: [],
    };
  },
  methods: {
    confirmEdit() {
      this.temp.id = new Date().getTime(); // unix timestamp
      this.temp.onStock = false;
      // console.log(this.temp);
      this.products.push(this.temp); // 把 temp 加入到 products;
      this.temp = {};
    },
  },
  created() {
    this.products = products;
  },
};

Vue.createApp(App).mount("#app");

簡單語法呈現大量資料於畫面上

// HTML
<div id="app">
  <table class="table">
    <thead>
      <tr>
        <th>標題</th>
        <th>圖片</th>
        <th>銷售狀態</th>
        <th>編輯</th>
      </tr>
    </thead>
    <tbody>
      <!-- :key 補上唯一值 -->
      <tr
        v-for="item in products"
        key="item.id"
        v-bind:class="{ 'table-success': item.onStock }"
      >
        <td>{{ item.name }}</td>
        <td>
          <img v-bind:src="item.imageUrl" width="300" alt="" />
        </td>
        <td>
          <input type="checkbox" v-model="item.onStock" />
          <!-- {{ item.onStock }} -->
        </td>
        <td>
          <button type="button" class="btn btn-outline-primary">編輯</button>
        </td>
      </tr>
    </tbody>
  </table>
  <form>
    <div class="mb-3">
      <label for="productName" class="form-label">產品名稱</label>
      <input
        type="text"
        id="productName"
        class="form-control"
        v-model="temp.name"
      />
    </div>
    <div class="mb-3">
      <img :src="temp.imageUrl" class="img-fluid d-block" alt="" width="300" />
      <label for="productImage" class="form-label">產品圖片</label>
      <input
        type="text"
        id="productImage"
        class="form-control"
        v-model="temp.imageUrl"
      />
    </div>
    <button type="button" class="btn btn-secondary" v-on:click="confirmEdit">
      更新
    </button>
  </form>
</div>
// JS
const products = [
  {
    id: "1",
    imageUrl:
      "https://images.unsplash.com/photo-1516906571665-49af58989c4e?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=300&q=80",
    name: "MacBook Pro",
    onStock: false,
  },
  {
    id: "2",
    imageUrl:
      "https://images.unsplash.com/photo-1512499617640-c74ae3a79d37?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80",
    name: "iPhone",
    onStock: false,
  },
];
const App = {
  data() {
    return {
      products: [],
      temp: {
        name: "卡斯伯",
        imageUrl:
          "https://images.unsplash.com/photo-1602526430780-782d6b1783fa?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
      },
    };
  },
  methods: {
    confirmEdit() {
      this.temp.id = new Date().getTime();
      this.temp.onStock = false;
      this.products.push(this.temp);
      this.temp = {};
    },
  },
  created() {
    this.products = products;
  },
};

Vue.createApp(App).mount("#app");

編輯你的資料狀態

// HTML
<div id="app">
  <table class="table">
    <thead>
      <tr>
        <th>標題</th>
        <th>圖片</th>
        <th>銷售狀態</th>
        <th>編輯</th>
      </tr>
    </thead>
    <tbody>
      <tr
        v-for="item in products"
        :key="item.id"
        :class="{'table-success': item.onStock}"
      >
        <td>{{ item.name }}</td>
        <td>
          <img :src="item.imageUrl" alt="" height="100" />
        </td>
        <td>
          <input type="checkbox" v-model="item.onStock" />
        </td>
        <td>
          <button
            type="button"
            class="btn btn-outline-primary"
            v-on:click="editItem(item)"
          >
            修改
          </button>
        </td>
      </tr>
    </tbody>
  </table>
  <form>
    <div class="mb-3">
      <label for="productName" class="form-label">產品名稱</label>
      <input
        type="text"
        id="productName"
        class="form-control"
        v-model="temp.name"
      />
    </div>
    <div class="mb-3">
      <img :src="temp.imageUrl" class="img-fluid d-block" alt="" width="300" />
      <label for="productImage" class="form-label">產品圖片</label>
      <input
        type="text"
        id="productImage"
        class="form-control"
        v-model="temp.imageUrl"
      />
    </div>
    <button type="button" class="btn btn-secondary" v-on:click="confirmEdit">
      更新
    </button>
  </form>
</div>
// JS
const products = [
  {
    id: "1",
    imageUrl:
      "https://images.unsplash.com/photo-1516906571665-49af58989c4e?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=300&q=80",
    name: "MacBook Pro",
    onStock: false,
  },
  {
    id: "2",
    imageUrl:
      "https://images.unsplash.com/photo-1512499617640-c74ae3a79d37?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80",
    name: "iPhone",
    onStock: false,
  },
];
const App = {
  data() {
    return {
      products: [],
      temp: {
        name: "筆電",
        imageUrl:
          "https://images.unsplash.com/photo-1602526430780-782d6b1783fa?ixid=MXwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
      },
    };
  },
  methods: {
    confirmEdit() {
      if (!this.temp.id) {
        // 新增資料
        this.temp.id = new Date().getTime();
        this.temp.onStock = false;
        this.products.push(this.temp);
        this.temp = {};
      } else {
        this.products.forEach((item, i) => {
          if (item.id === this.temp.id) {
            this.products[i] = this.temp;
          }
        });
        this.temp = {};
      }
    },
    editItem(item1) {
      // console.log("editItem", item1);

      // 陷阱
      // this.temp = item1;

      // 淺層拷貝
      this.temp = { ...item1 };
    },
  },
  created() {
    this.products = products;
  },
};

Vue.createApp(App).mount("#app");

基礎章節作業: 完成新增、編輯商品項目

// HTML
<div id="app">
  <div class="text-end">
    <button class="btn btn-primary" type="button" v-on:click="addItem">
      新增
    </button>
  </div>
  <table class="table">
    <thead>
      <tr>
        <th>標題</th>
        <th>圖片</th>
        <th>銷售狀態</th>
        <th>編輯</th>
      </tr>
    </thead>
    <tbody>
      <tr
        v-for="item in products"
        :key="item.id"
        :class="{'table-success': item.onStock}"
      >
        <td>{{ item.name }}</td>
        <td>
          <img :src="item.imageUrl" alt="" height="100" />
        </td>
        <td>
          <input type="checkbox" v-model="item.onStock" />
        </td>
        <td>
          <button
            type="button"
            class="btn btn-outline-primary"
            v-on:click="editItem(item)"
          >
            修改
          </button>
        </td>
      </tr>
    </tbody>
  </table>
  <form v-if="isNew || temp.id">
    <div class="mb-3">
      <label for="productName" class="form-label">產品名稱</label>
      <input
        type="text"
        id="productName"
        class="form-control"
        v-model="temp.name"
      />
    </div>
    <div class="mb-3">
      <label for="productImage" class="form-label">產品圖片</label>
      <input
        type="text"
        id="productImage"
        class="form-control"
        v-model="temp.imageUrl"
      />
    </div>
    <button type="button" class="btn btn-secondary" v-on:click="confirmEdit">
      更新
    </button>
  </form>
</div>
// JS
const products = [
  {
    id: "1",
    imageUrl:
      "https://images.unsplash.com/photo-1516906571665-49af58989c4e?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=300&q=80",
    name: "MacBook Pro",
    onStock: false,
  },
  {
    id: "2",
    imageUrl:
      "https://images.unsplash.com/photo-1512499617640-c74ae3a79d37?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80",
    name: "iPhone",
    onStock: false,
  },
];
const App = {
  data() {
    return {
      products: [],
      temp: {},
      // 狀態,決定是否為新增產品
      isNew: false,
    };
  },
  methods: {
    editItem(item) {
      this.temp = { ...item };
    },
    confirmEdit() {
      if (!this.temp.id) {
        this.temp.id = new Date().getTime();
        this.temp.onStock = false;
        this.products.push(this.temp);
      } else {
        this.products.forEach((item, i) => {
          if (item.id === this.temp.id) {
            this.products[i] = this.temp;
          }
        });
      }
      this.temp = {};
      this.isNew = false;
    },
    addItem() {
      this.isNew = true;
      this.temp = {};
    },
  },
  created() {
    this.products = products;
  },
};

Vue.createApp(App).mount("#app");