###### 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模組化