###### 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中前內(事件),後外(事件)

### 利用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架構圖

### **由四個結構所組成,整個 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模組化