---
# System prepended metadata

title: Vue學習 Day4
tags: [Vue相關內容]

---

###### tags: `Vue相關內容`
# Vue學習 Day4
## 元件的分類
展示型元件 (Presentation)
容器型元件 (Container)
互動型元件 (Interactive)
功能型元件 (Functions)
> **component中的template僅能以一個tag去包多個tag**

```javascript=
var app = new Vue({
	data: {
		count: 0
	}
})

Vue.component('example', {
	template: `
		<p> appCount: {{ appCount }} </p>
	`,
	computed: {
		appCount: function () {
			return app.$data.count;
		}
	},
	created() {
		app.$on('appEvent', function () {
			this.count++;
		});
		app.$emit('appEvent');
	}
})

var render = new Vue({
	el: '#app'
})
```

### props(父=>子)及emits(子=>父)
1.props口訣：前面是屬性，後面是值
2.emits口訣：元件內this.emit推，外層接收 ; 元件HTML中前內(事件)，後外(事件)
![](https://i.imgur.com/f942TL4.jpg)

### 利用ref驅動component中的方法
app.js
```javascript=
Vue.component('example', {
	template: `
		<div>test component</din>
	`,
	created: function () {
		this.$on('open', function () {
			console.log('執行 open finction');
		})
	}
})

var app = new Vue({
	el: '#app',
	data: {

	},
	methods: {
		clickEvent: function () {
			this.$refs.comp.$emit('open');
		}
	}
})
```
index.html
```javascript=
<div id="app">
    <example ref="comp"></example>
    <button @click="clickEvent">按我</button>
  </div>
```

### slot用法
> 位置依照template中所定義的位置顯示
```javascript=
template: `
		<div>
			<header>
				<slot name="head">標頭</slot>
			</header>
			<section>
				<slot>內容區域</slot>
			</section>
			<footer>
				<slot name="foot">頁尾</slot
			</footer>
		</din>
	`
```
index.html
```javascript=
<example>
      <p>客製化內容區域</p>
      <p slot="head">這是標頭</p>
      <p slot="foot">這是頁尾~</p>
</example>

$>>
這是標頭

客製化內容區域

這是頁尾~
```



## JavaScript異步處理Promise
### Promise簡介
* ES6推出的新特性
* 解決Callback Hell困境
* 針對異步處理所設計
* 初始狀態為:pending=>可變為:
    * 已實現狀態(fulfilled)
    * 已拒絕狀態(rejected)

**語法**
```javascript=
// 建立Promise物件 - 傳統函式
const promise = new Promise(function(resolve, reject) {
    // 成功時
    resolve(value)
    // 失敗時
    reject(reason)
});

// 建立Promise物件 - 箭頭函式
const promise = new Promise((resolve, reject) => {
    // 成功時
    resolve(value)
    // 失敗時
    reject(reason)
});

// 執行完成後的處理方式
promise.then((value) => {
    // on fulfillment(已實現時)
}, (reason) => {
    // on rejection(已拒絕時)
}).catch((reason) => {
        // 執行錯誤處理
})
```
## Ajax (Asynchronous JavaScript and XML)

> **早期用法**
```javascript=
function reqListener () {
    console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load",reqListener);
oReq.open("GET","http://www.example.org/example.txt");
oReq.send();
```
### jQuery - ajax
```javascript=
$.ajax({
	//API連結
	url: './test.json',
	// 要送出的資料
	data: {
		// value: 'test'
	},
	// HTTP method (POST 或 GET)
	type: 'GET',
	// 資料類型
	dataType: 'json',
})
	// 執行成功
	.done(function (json) {
		console.log('done!!');
		console.log(json);
	})
	// 執行失敗
	.fail(function (xhr, status, errorThrown) {
		console.log('Error :' + errorThrown);
		console.log('Status: ' + status);
		console.dir(xhr);
	})
	// 成功或失敗都執行
	.always(function (xhr, status) {
		console.log('always done!!');
	})
```
### axios
* node.js中發送HTTP Request
* 支持Promise API
* 客戶端支援防止CSRF
* 提供併發的請求介面

> **NetWork中可以看Header和Preview得知傳出以及使用API的內容是否正確**
```javascript=
axios.get('https://cloud.culture.tw/frontsite/trans/SearchShowAction.do', {
	params: {
		method: 'doFindTypeJ',
		category: 8
	},
}).then(function (response) {
	console.log(response);
}).catch(function (error) {
	console.log(error);
});
```

### Fetch Ajax(需再了解)
```javascript=
function get(url, params = {}) {
	var urlObj = new URL(url);
	urlObj.search = new URLSearchParams(params);
	return fetch(new Request(urlObj, {
		method: 'GET',
	})).then((response) => {
		return response.json();
	}).catch((error) => {
		console.log(error);
	})
}

get('https://cloud.culture.tw/frontsite/trans/SearchShowAction.do', {
	method: 'doFindTypeJ',
	category: 8
}).then(function (response) {
	console.log(response);
}).catch(function (error) {
	console.log(error);
});
```

### JavaScript 異步處理 async/await
```javascript=
function numberValidator(value) {
	return new Promise(function (resolve, reject) {
		console.log(value);
		setTimeout(function () {
			if (typeof (value) === 'number')
				resolve('已成功')
			else
				reject('已失敗')
		}, 3000)
	})
}

// 使用async和await改寫更易讀
async function printValidResult(value) {
	try {
		const result = await numberValidator(value);
		console.log(result);
	} catch (err) {
		console.log('error: ', err);
	}
}

printValidResult('10')


//原寫法
// numberValidator('3').then((value) => {
// 	console.log(value);
// }).catch((reason) => {
// 	console.log(reason);
// })
```

### **上上面的Fetch改寫**
```javascript=
async function get(url, params = {}) {
	var urlObj = new URL(url);
	urlObj.search = new URLSearchParams(params);

	const response = await fetch(new Request(urlObj, {
		method: 'GET',
	}));
	const json = await response.json();

	return json;
}


get('https://cloud.culture.tw/frontsite/trans/SearchShowAction.do', {
	method: 'doFindTypeJ',
	category: 8
}).then(function (response) {
	console.log(response);
}).catch(function (error) {
	console.log(error);
});
```

## Vuex
### **為何使用Vuex?**
* 整合不同頁面/元件的共用資料
* 整合不同頁面/元件的共用方法(function)
* 使用雙向資料綁定，避免產生難以理解的Code
* 可簡化資料傳遞的方式

### 安裝Vuex
1. vue init webpack-simple vue8-1
1. yarn install
1. yarn add vuex
1. yarn dev

### **Vuex特性**
* 單向資料流
* 具有狀態機(store)管理系統所有共用狀態

> Vuex架構圖
![](https://i.imgur.com/dOvCTHj.jpg)

### **由四個結構所組成，整個 Vuex 的方法也稱為 store**
* **state:**
    * 為單一狀態數
    * Vuex與全局變數的不同:
        * Vue的Component若讀取state，當store產生變化時Component會一併更新。
        * 無法直接更新store，必須透過mutation的commit更新。
* **gatter:**
    * 從store衍生的屬性，類似一般元件的computed屬性。
* **mutation:**
    * 處理同步程式的函式
    * 唯一直接更新state的地方
* **action:**
    * 可以處理任何的異步操作(Promise)
    * 必須透過mutation來更新state




### 用法
store.js
```javascript=
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const store = new Vuex.Store({
     state: {
          shoppingCart: [],
          count: 0,
          productions: [
               { id: 1, name: '紅茶', price: 30 },
               { id: 2, name: '綠茶', price: 25 },
               { id: 3, name: '奶茶', price: 40 },
               { id: 4, name: '珍珠奶茶', price: 50 },
               { id: 5, name: '咖啡', price: 35 },
          ],
     },
     getters: {
          index(state, getters, rootState, rootGetters) {
               return state.count + 1;
          },
          max(state) {
               return state.productions.reduce((a, b) => {
                    return (a > b.price) ? a : b.price;
               }, 0);
          },
          item(state) {
               return id => state.productions.find(el => el.id === id)
          },
          shoppingList(state, getters) {
               return state.shoppingCart.map(function (item, index, array) {
                    return getters.item(item)
               })
          },
          totalPrice(state, getters) {
               return getters.shoppingList.reduce((a, b) => {
                    return a + b.price
               }, 0);
          }
     },
     mutations: {
          addProd(state, payload) {
               state.shoppingCart.push(payload);
          }
     },
     actions: {
          doAddProd({ commit }, productionID) {
               commit('addProd', productionID);
          }
     }
});

export default store;
```

App.vue
```javascript=
<template>
  <div id="app">
    <select v-model="selectProduction">
      <option value="">請選擇</option>
      <option v-for="item in prods" :value="item.id">{{ item.name }}</option>
    </select>
    <button @click="buy">購買</button>
    <br /><br />
    <ul v-for="item in shoppingList">
      <li>{{ item.name }} - {{ item.price }} 元</li>
    </ul>
    總價: {{ totalPrice }}
  </div>
</template>

<script>
import { mapState, mapGetters, mapActions } from "vuex";

export default {
  data: () => ({
    selectProduction: "",
    msg: "Example - Action and Mutations",
  }),
  computed: {
    ...mapGetters(["index", "max", "shoppingList", "totalPrice"]),
    ...mapState({
      prods: (state) => state.productions,
    }),
    itemA() {
      return this.$store.getters.item(1);
    },
    itemB() {
      return this.$store.getters.item;
    },
  },
  methods: {
    ...mapActions(["doAddProd"]),
    buy() {
      if (this.selectProduction != "") {
        this.doAddProd(this.selectProduction);
        this.selectProduction = "";
      }
    },
  },
};
</script>

<style lang="scss">
</style>
```

### Vuex模組化