什麼是VueX 在一般的Vue中,同層級的元件之間,我們可以利用eventbus來做同層級的溝通, 但是,eventbus僅止於做簡單的溝通而已。 若我們想利用全域變數來讓同層級的Vue元件做構通,就又會失去Vue雙向綁定的特性。 所以,我們將所有的同階層 或 父子層的元件都丟到VueX,由VueX來做管理, 此時,我們就可以透過VueX來做到同階層的互相溝通,還有,父子層的上下溝通, 同時,又不失去VueX雙向綁定的特性。
VueX - 重要的成員屬性 state : 儲存資料狀態actions : 如同先前提過的methods
,進行非同步與取得資料,但是,特別注意,在這一個功能中並不會改變資料的狀態 。getter : 如同computed
,在資料呈現之前會做一些過濾的動作,就會在這個功能中做處理。mutations : 改變資料內容的方法,而在此功能中,不會處理一些非同步的行為喔 ,即像是將遠端的api取進來這種事情就不會在這邊做。
小插曲-有關如何開啟課堂上提供的課程vueX檔案 首先,輸入npm install
,先將node_modules這個資料夾安裝完成, 接著,安裝完成後,就輸入npm start
,此時,編譯器應該就會跳你可以開啟的網頁的網址local:8080之類的東西。 有關這個npm start
的啟動Vue專案指令,你可以直接去package.json的檔案中, 看一下script部分有哪些指令,像課堂上的專案中就有以下的指令
1 2 3 4 5 6 "scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", "lint": "eslint --ext .js,.vue src", "build": "node build/build.js" }
你可以看到npm start
等同於npm run dev
的指令,你就選擇要輸入npm start
或npm run dev
都可以打開專案檔囉。 也因為課堂上的專案檔是用Vue2寫的,所以,沒有指令npm run serve
是很正常的喔。
新增一個 Store 管理網站資料狀態 在我實作的專案檔中,當我在商品頁面按下加入購物車,Navbar的購物車資訊是不會跟著連動作增減的,所以,這邊握們要利用VueX來達到它們可以彼此連動的效果。
在這邊呢,我們先拿loading這個特效入手,將判斷是否啟用這個效果的判斷條件加入到VueX中。
step1,先輸入指令npm install vuex --save
來安裝VueX的套件 step2,啟用VueX 我們先到main.js中,寫入
1 2 import Vuex from 'vuex' Vue.use(Vuex);
以此來啟用Vuex套件。
step3 我們在src資料夾中,新增一個store資料夾,並在這個資料夾中新增一個index.js的檔案, 這個檔案就是用來彙整所有VueX的行為。 接著,你就在這個store資料夾中的index.js檔案裡輸入以下的內容
1 2 3 4 5 6 import Vue from 'vue'; import VueX from 'vuex'; Vue.use(VueX); export default new VueX.Store({ });
就是在這個js檔案中啟用VueX和Vue元件。
step4. 我們要在main.js中,引入這個store資料夾底下的index.js檔案
1 2 3 4 5 6 7 8 9 import store from './store' // 引入store檔案 new Vue({ el: '#app', router, store, // 新增store這個成員屬性 components: { App }, template: '<App/>', });
step5. 先到store資料夾中的index.js檔案中, 加入state屬性,並新增一個isLoading成員屬性,並設定它為false
。
1 2 3 4 5 6 ---index.js--- export default new VueX.Store({ state:{ isLoading: true, }, });
step6. 接著,你到App.vue中將原本有關isLoading成員屬性的程式碼內容給註解掉,但是,不要連HTML中的isLoading內容都註解喔,那邊的不用註解。 然後,新增一個computed
,接著,在裡面新增一個isLoading屬性,並讓他吃到store變數的isLoading變數,如此,你應該就可以看到你的 網頁頁面一直有loading的圈圈再轉囉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ---App.vue--- ---HTML--- <Loading :active.sync="isLoading"></Loading> // 吃到isLoading的回傳值 ---JavaScript--- <script> export default { name: 'App', data() { return { cart: { carts: [], }, // isLoading: false, // 註解掉有關isLoading的部分 }; }, computed: { isLoading() { return this.$store.state.isLoading; // 新增isLoading,並讓它吃到store中的isLoading值 }, }, }; </script>
記得,看到成功的呈現結果後,要把index.js中的isLoading的值,改回false
喔,不然你的頁面會一直處在轉圈圈的狀態。
step7. 接著,你到Home.vue元件檔中,先將HTML文件中的isLoading元件的部分刪掉,因為,現在這個元件要統一由App.vue外層元件來呈現。 再來,就在Home.vue中將原先使用isLoading的部分,全部改成去更改store資料夾中的index.js的isLoading的資料狀態,藉此,來決定是否要呈現Loading的效果囉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ---Home.vue--- ---JavaScript--- <script> export default { name: 'Home', data() { return { products: [], searchText: '', categories: [], // isLoading: false, // 將原本的isLoading的內容註解掉 }; }, methods: { getProducts() { const vm = this; const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/products/all`; // vm.isLoading = true; // 將原本的isLoading的內容註解掉 this.$store.state.isLoading = true; // 切換store資料夾中的isLoading的屬性切換 this.$http.get(url).then((response) => { vm.products = response.data.products; console.log('取得產品列表:', response); vm.getUnique(); // vm.isLoading = false; // 將原本的isLoading的內容註解掉 this.$store.state.isLoading = false; // 切換store資料夾中的isLoading的屬性切換 }); } }, created() { this.getProducts(); }, }; </script>
藉由以上的方式就完成將isLoading交由VueX來管理,並指讓外層元件App.vue來呈現Loading的效果囉~
actions 及 mutations 改變資料狀態 在這個地方,我們會利用actions
及 mutations
來切換isLoading的資料狀態。 就不是像上一堂課程中直接修改this.$store.state.isLoading
的內容。 step1. 所以,我們就在store資料夾中的index.js檔案中新增actions
及 mutations
的內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ---index.js--- export default new VueX.Store({ state: { isLoading: false, }, actions: { updateLoading(context, status) { context.commit('LOADING', status); }, }, mutations: { LOADING(state, status) { state.isLoading = status; }, }, });
上面可以看到,我們在actions
中,新增了一個updateLoading函式來取得isLoading資料。 並在updateLoading函式中,呼叫mutations
中的LOADING函式,藉此修改state的isLoading屬性值。 從這邊我們就可以看到在action
s中,我們只能接收資料內容。 在mutations
中,我們可以修改資料的狀態。
那在actions
裡面的函式有context
這個參數,在VueX的官方網站 ,有介紹, 它是一個參數,可以取得VueX中的許多參數值,所以,看到我們藉由它的commit
成員來呼叫到LOADING函式,利用它來做actions
和mutations
之間的橋樑。
step2. 接著,我們就修改Home.vue元件檔中原本this.$store.state.isLoading
的內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ---Home.vue--- <script> export default { methods: { getProducts() { const vm = this; const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/products/all`; vm.$store.dispatch('updateLoading', true); // 加入這一行來呼叫index.js中的updateLoading函式,並帶入參數true this.$http.get(url).then((response) => { vm.products = response.data.products; console.log('取得產品列表:', response); vm.getUnique(); vm.$store.dispatch('updateLoading', false); }); }, }; </script>
上面這邊的內容,我們就可以看到我們在Home.vue中,呼叫了index.js的updateLoading函式,並帶入參數true
,藉此能更改isLoading的參數值。
Vuex 的嚴謹模式 在VueX的檔案中加入strict: true
這段程式碼,就可以讓你的VueX檔案呈現嚴謹模式,為的是來提醒你在VueX中哪邊有寫錯,或者更改了那些不應該更改的內容囉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 export default new VueX.Store({ strict: true, // 加入VueX的嚴謹模式 state: { isLoading: false, }, actions: { updateLoading(context, status) { context.commit('LOADING', status); }, }, mutations: { LOADING(state, status) { state.isLoading = status; }, }, });
使用 Actions 取得遠端資料 此課程教導將原先在Home元件中,取得購物車資料的程式碼,移到VueX中,交由VueX來執行這些取得資訊的動作。 step1. 在store資料夾中的index.js檔案中,新增以下內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 ---index.js--- import Vue from 'vue'; import VueX from 'vuex'; import axios from 'axios'; // 引入axios元件,因為index.js不是Vue元件,需要直接使用axios來取用遠端資料 Vue.use(VueX); export default new VueX.Store({ strict: true, state: { isLoading: false, products: [], // 新增products陣列 categories: [], // 新增categories陣列 }, actions: { updateLoading(context, status) { context.commit('LOADING', status); }, getProducts(context) { const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/products/all`; context.commit('LOADING', true); axios.get(url).then((response) => { console.log('取得產品列表:', response); context.commit('PRODUCTS', response.data.products); // 呼叫mutations中的PRODUCTS函式 context.commit('CATEGORIES', response.data.products); // 呼叫mutations中的CATEGORIES函式 context.commit('LOADING', false); }); }, }, mutations: { LOADING(state, status) { state.isLoading = status; }, PRODUCTS(state, payload) { // 將products陣列塞入從遠端取得的資料 state.products = payload; }, CATEGORIES(state, payload) { // 將遠端取的的資料的分類儲存到categories中 const categories = new Set(); payload.forEach((item) => { categories.add(item.category); }); state.categories = Array.from(categories); }, }, });
以上,我們可以看到我們在index.js檔案中,新增了products 和 categories陣列,用來儲存從遠端取得資料的內容。 那我們新增了PRODUCTS 和 CATEGORIES這兩個mutations
的方法,用來儲存products 和 categories的資料內容。
step2. 接著,我們要修改Home.vue檔案,直接在這個檔案中呼叫index.js的getProducts函式,取得資料,並利用computed
來即時更新頁面中的內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ---Home.vue--- <script> export default { name: 'Home', data() { return { searchText: '', }; }, computed: { categories() { return this.$store.state.categories; // 回傳sotre元件中的categories內容 }, products() { return this.$store.state.products; // 回傳sotre元件中的products內容 }, }, methods: { getProducts() { this.$store.dispatch('getProducts'); // 呼叫index.js檔案中的getProducts方法,來取得遠端資料 }, }, }; </script>
以上這個步驟,我們就可以透過vuex取得遠端資料後,接著,在元件檔中呼叫vuex取得遠端資料的方法。最後,當VueX元件中的資料有變動時,我們就在元件檔中利用computed
來即時更新頁面上的內容。
Payload 傳遞物件參數 這個小節是在教導將取得、刪除、加入購物車的內容通通移植到VueX中,去操作。 step1. 首先,先將取得購物車的內容移到VueX中。 在App.vue元件檔中,我們先將整個getCart的內容移到index.js的actions
中。 並在index.js中,新增cart的成員屬性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ---index.js--- state: { isLoading: false, products: [], categories: [], cart: { // 新增cart屬性 carts: [], }, }, actions: { getCart(context) { // 新增取得購物車內容的屬性 const vm = this; context.commit('LOADING', true); const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/cart`; axios.get(url).then((response) => { if (response.data.data.carts) { vm.cart = response.data.data; } context.commit('LOADING', false); context.commit('CART', vm.cart); // 呼叫mutations中的CART函式,來將資料塞入成員屬性中 }); }, }, mutations: { LOADING(state, status) { state.isLoading = status; }, CART(state, payload) { // 在mutations中新增CART方法,將資料塞入cart中 state.cart = payload; }, }
**注意~~~~**以上這個範例,你可以看到只有單純切換布林值的話,該mutations的函式(LOADING函式)參數是用status帶入,而你是要傳一筆大資料的話,mutations中的函式(CART函式)是用payload來當參數傳入。
傳遞參數到actions中,只能傳遞一個參數 當我們要傳遞多個參數的時候,我們可以用物件將這些參數包裹起來,再將這個物件傳到actions
中。 如此,這樣就可以解決只能傳遞一個參數的限制囉。 我們在index.js檔案中,加入購物車 和 刪除購物車中商品的功能 step1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 ---index.js--- export default new VueX.Store({ actions: { removeCart(context, id) { const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/cart/${id}`; context.commit('LOADING', true); axios.delete(url).then((response) => { context.commit('LOADING', false); context.dispatch('getCart'); console.log('刪除購物車項目', response); }); }, addtoCart(context, { id, qty }) { const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/cart`; context.commit('LOADING', true); const item = { product_id: id, qty, }; axios.post(url, { data: item }).then((response) => { context.commit('LOADING', false); context.dispatch('getCart'); console.log('加入購物車:', response); }); }, } }) ---Home.vue--- <script> export default { methods: { addtoCart(id, qty = 1) { this.$store.dispatch('addtoCart', { id, qty }); }, }, }; </script> ---App.vue--- <script> export default { name: 'App', data() { return { }; }, methods: { getCart() { this.$store.dispatch('getCart'); }, removeCart(id) { this.$store.dispatch('removeCart', id); }, }, computed: { isLoading() { return this.$store.state.isLoading; }, cart() { console.log('購物車', this.$store.state.cart); return this.$store.state.cart; }, }, created() { this.getCart(); }, }; </script>
首先,你可以看到,我們在index.js檔案中的addtoCart函式,就是用包裹物件的方式,將多個資料傳遞進去。 另外,我們在App.vue這個最外層的元件檔,執行取得購物車 和 刪除購物車的功能, 並利用computed來回船當下購物車的資料狀態。 第三,我們在Home.vue中有新增一個addtoCart的加入購物車的函式。 整體的運作過程就是,當我們在Home.vue中將商品加入購物車,此時,在VueX中會更改state.cart的內容, 而在App.vue中,就有利用computed來連動VueX中的state的cart資料。 經過以上的這種運作模式,就實現了跨父子元件階層來存取相同資料的運作囉。
Vuex 中的 getters 及 mapGetters, mapActions 前面有說到在VueX中的getters
的功用就如同computed
的功能一般。 所以,這邊我們把想要呈現在畫面上的computed
內容,搬到VueX的getters
裡面。 Step1. 我們在index.js檔案中,加入getters
的屬性。
1 2 3 4 5 6 7 8 9 10 11 ---index.js--- export default new VueX.Store({ getters: { categories(state) { return state.categories; }, products(state) { return state.products; }, }, });
接著,你把原本在Home.vue中的computed
回傳categories 和 products的部分刪掉。 Step2. 那我們要怎麼將在index.js中的categories 和 products呈現在畫面中呢? 我們就在Home.vue中引入VueX的mapGetters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ---Home.vue--- ---HTML--- <!-- 左側選單 (List group) --> <div class="list-group sticky-top"> <a class="list-group-item list-group-item-action" href="#" @click.prevent="searchText = item" :class="{ 'active': item === searchText}" v-for="item in categories" :key="item"> // 吃到categories的資料 <i class="fa fa-street-view" aria-hidden="true"></i> {{ item }} </a> <a href="#" class="list-group-item list-group-item-action" @click.prevent="searchText = ''" :class="{ 'active': searchText === ''}"> 全部顯示 </a> </div> ---JavaScript--- <script> import { mapGetters } from 'vuex'; // 這邊是用解構的方式將VueX的mapGetters取出來 computed: { ...mapGetters(['categories', 'products']), } </script>
用以上的方法我們就可以利用mapGetters
的方式將VueX中的categories和products這兩個資料內容取出來,並利用computed
的方式,將這兩個資料呈現在Home.vue的話中。 而Home.vue的html文件部分,加入categories 和 products就可以吃到這兩個資料了。 這邊的資料存取方式,是利用了解構特性中,當資料名稱和成員屬性名稱相同的時候, 就可以只寫成員屬性名稱即可。
step3. 我們也可以利用mapActions
將VueX中的某些actions
裡的函式也帶進來。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ---Home.vue--- ---JavaScript--- <script> import { mapGetters, mapActions } from 'vuex'; // 將mapActions也從vuex中取出來 export default { methods: { addtoCart(id, qty = 1) { this.$store.dispatch('addtoCart', { id, qty }); }, ...mapActions(['getProducts']), // 將getProducts取出來 }, }; </script>
以上,我們也就利用了mapActions
來調用在vuex中的getProducts函式。
沒有引入要傳遞的函式才能用mapActions 以上範例你可以看到在Home.vue元件檔中得addtoCarts函式我們是沒有對它使用mapActions
的, 原因是addtoCart需要傳遞參數到index.js中,所以,這類型要傳遞參數的函式我們不會對它使用mapActions
喔~~
模組化資料運用 在這課堂上的課程內容,主要有兩種行為,一種是跟產品(Products)有關,另一種是跟購物車有關(Carts),所以,在這邊我們會利用Vuex的模組化管理將專案檔的內容拆分成為這兩大類。 那在專案檔中的VueX,產品和購物車的內容原本是攪和在一起的,那課堂上是只有將產品部分模組化。 step1. 這邊我們在store資料夾中,新增一個products.js檔案。 然後把原本index.js檔案中的內容貼到products.js檔案中,並且只留下跟產品相關的內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ---product.js--- import axios from 'axios'; // 引入axios export default { state: { products: [], categories: [], }, actions: { getProducts(context) { const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/products/all`; context.commit('LOADING', true); axios.get(url).then((response) => { console.log('取得產品列表:', response); context.commit('PRODUCTS', response.data.products); context.commit('CATEGORIES', response.data.products); context.commit('LOADING', false); }); }, }, mutations: { PRODUCTS(state, payload) { state.products = payload; }, CATEGORIES(state, payload) { const categories = new Set(); payload.forEach((item) => { categories.add(item.category); }); state.categories = Array.from(categories); }, }, getters: { categories(state) { return state.categories; }, products(state) { return state.products; }, }, }
step2. 回到store資料夾中的index.js檔案,我們把跟產品相關的內容刪掉,因為,要區分開來 然後,在index.js中,將剛剛的product.js給引入進來,並且將它加到modules的屬性中
1 2 3 4 5 6 7 8 9 10 11 12 13 ---index.js--- import Vue from 'vue'; import VueX from 'vuex'; import axios from 'axios'; import productModule from './product'; // 引入product.js並將它命名為productModule變數 Vue.use(VueX); export default new VueX.Store({ modules: { productModule, 將該變數加入到modules中 }, });
模組中的區域變數和全域變數 先介紹一下,在模組中的state是屬於區域變數, 而actions
, mutations
, getters
都是屬於全域變數。 而這也是為什麼我們可以直接在本專案中的Home.vue元件檔,直接使用store資料夾中的index.js模組中的actions
, mutations
, getters
的原因,因為它們都是全域變數。 但是,這樣有一個風險,如果在同一層的資料夾中,也就是在store資料夾中,萬一有其他的模組的函式的取名跟index.js的函式一樣,這樣會造成外部元件在調用這些函式時,造成衝突。 也因為有這樣的衝突狀況,所以,我們會將模組中的變數設定成區域變數,如此一來,就不會有相衝突的問題囉。
step3. 在Home.vue取用product.js模組中的products資料。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ---Home.vue--- ---JavaScript--- <script> import { mapGetters, mapActions } from 'vuex'; export default { methods: { addtoCart(id, qty = 1) { console.log(this.$store.state.productModule.products); // 提取productModule中的products資料內容 this.$store.dispatch('addtoCart', { id, qty }); }, ...mapActions(['getProducts']), }, }; </script>
你可以看到我們取用了productModule中的products資料。
語法namespaced:true,從全域變數改成區域變數 step4. 我們想要將product.js模組中的actions
, mutations
, getters
從原本的全域變數改成區域變數,來跟外部模組的變數做區分。 首先,在product.js中加入namespaced:true
將actions
, mutations
, getters
都改為區域變數。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ---product.js--- export default { namespaced: true, // 將actions, mutations, getter都改為區域變數。 state: { products: [], categories: [], }, actions: { getProducts(context) { const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/products/all`; context.commit('LOADING', true); axios.get(url).then((response) => { console.log('取得產品列表:', response); context.commit('PRODUCTS', response.data.products); context.commit('CATEGORIES', response.data.products); context.commit('LOADING', false); }); }, }, mutations: { PRODUCTS(state, payload) { state.products = payload; }, CATEGORIES(state, payload) { const categories = new Set(); payload.forEach((item) => { categories.add(item.category); }); state.categories = Array.from(categories); }, }, getters: { categories(state) { return state.categories; }, products(state) { return state.products; }, }, };
接著,你要到Home.vue元件檔中,改變引入product.js模組函式的內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ---Home.vue--- <script> import { mapGetters, mapActions } from 'vuex'; export default { computed: { filterData() { const vm = this; if (vm.searchText) { return vm.products.filter((item) => { console.log(item.category.toLowerCase()); const data = item.category.toLowerCase().includes(vm.searchText.toLowerCase()); return data; }); } return this.products; }, ...mapGetters('productModule', ['categories', 'products']), // 在引入內容的前面要加入這些變數所處在的模組變數名稱 }, methods: { addtoCart(id, qty = 1) { console.log(this.$store.state.productModule.products); this.$store.dispatch('addtoCart', { id, qty }); }, ...mapActions('productModule', ['getProducts']), // 在引入內容的前面要加入這些變數所處在的模組變數名稱 }, }; </script>
利用以上這兩個操作,就能將product.js模組中的actions
, mutations
, getters
都改為區域變數,並在Home.vue中調用這些已經變成區域變數的內容。
step5. 那這個時候,你的網頁應該會跳出有關LOADING 這個變數的錯誤。 這個原因是,在product.js中,我們有使用LOADING 這個變數,但是,它並不知道LOADING是一個global的LOADING, 它以為那是它自己的LOADING變數,而這也就是會跳LOADING是未知變數錯誤的原因喔~ 所以,我們要改變一下在product.js模組中,使用LOADING的寫法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ---product.js--- export default { namespaced: true, actions: { getProducts(context) { const url = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/products/all`; context.commit('LOADING', true, { root: true }); // 在LOADING 後面加上了{ root: true }來讓product.js模組知道這是一個global的LOADING變數 axios.get(url).then((response) => { console.log('取得產品列表:', response); context.commit('PRODUCTS', response.data.products); context.commit('CATEGORIES', response.data.products); context.commit('LOADING', false, { root: true }); // 在LOADING 後面加上了{ root: true }來讓product.js模組知道這是一個global的LOADING變數 }); }, }, };
經由以上的修改之後,你的網頁就不會再跳出相關的錯誤囉~~
VueX小結論 以上這些操作步驟就是利用VueX來管理專案檔,並讓通用變數可以跨階層被取用的方法囉~ 那回到最一開始講的,購物車資料連動的效果。 其原因來自,Home.vue這個子元件是直接去修改VueX中的cart購物車資料,而App.vue是取用VueX中的cart資料,來呈現在畫面上。 所以,由上面的操作流程可以知道,父子元件都是對VueX中的同一個成員屬性的內容去操作,那當然就會有連動的效果囉。