---
# System prepended metadata

title: Vue 學習
tags: [vue]

---

---
title: Vue 學習
tags: vue
---
> [中文文檔](https://v3.cn.vuejs.org/guide/introduction.html)

> [CSS 函式庫 Bootstrap](https://bootstrap5.hexschool.com/)

> [chrome 擴充](https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg)
![](https://i.imgur.com/n5S2J9Z.png)

### VSCode 相關套件
- [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
- [Vue 官方提供的 Vue 整合插件](https://marketplace.visualstudio.com/items?itemName=octref.vetur)
- [Vue 3 Snippets](https://marketplace.visualstudio.com/items?itemName=hollowtree.vue-snippets)

---

### 運作概念
**MVVM** 全名為 Model-View-ViewModel
* M 代表 Model(存放資料)
* V 代表 View(畫面顯示)
* VM 稱作 ViewModel(資料與畫面互動)

![](https://i.imgur.com/9KLZNLk.png)

### createApp

```javascript
<div id="app">
  {{counter}}
  {{text}}
</div>

<script>
Vue.createApp({
  data() {
    return {
      counter: 5,
      text: '這是一段話',
    }
  }
}).mount('#app')
</script>
```

![](https://i.imgur.com/NBR7ek9.png)

### 起手式

:::info
可輸入 `div.app` or `div#app`
:::

```javascript
<div id="app">
  {{ counter }}
  <button type="button" v-on:click="clickMe"> 按我 </button>
</div>

<script>
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')
</script>
```
![](https://i.imgur.com/nXPjXP3.png)

### 雙向綁定
```javascript
<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>

<script>
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');
</script>
```

### 資料操作

![](https://i.imgur.com/zu2adKJ.png)

```javascript
<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>

<script>

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();//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');
</script>
```

### 多筆資料渲染

![](https://i.imgur.com/uo6M0na.png)

```javascript
<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" 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>
```

### 指令

![](https://i.imgur.com/Mj65NRo.png)

#### `v-for`
```javascript
<ul>
    <li v-for="(item, key) in products"> {{key+1}} . {{item.name}}/{{item.price}}元</li>
</ul>
```
```javascript
products: [
    {
      name: '蛋餅',
      price: 30,
      vegan: false
    },
    {
      name: '飯糰',
      price: 35,
      vegan: false
    },
    {
      name: '小籠包',
      price: 60,
      vegan: false
    },
    {
      name: '蘿蔔糕',
      price: 30,
      vegan: true
    },
],
```

![](https://i.imgur.com/fOPfPKm.png)

```javascript
<ul>
    <li v-for="(item, key) in productsObj"> {{key}} . {{item.name}}/{{item.price}}</li>
  </ul>
```
```javascript
productsObj: {
    chineseOmelette: {
      name: '蛋餅',
      price: 30,
      vegan: false
    },
    riceBall: {
      name: '飯糰',
      price: 35,
      vegan: false
    },
    soupDumpling: {
      name: '小籠包',
      price: 60,
      vegan: false
    },
    radishCake: {
      name: '蘿蔔糕',
      price: 30,
      vegan: true
    }
},
```
![](https://i.imgur.com/r1p0TPq.png)
