Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式,Vuex抽取了各個組件的共享部分,以全局單例模式進行狀態的管理。在原生vue中各個組件之間傳值使用的是props和event,若是組件嵌套層數過多使用props進行傳參會十分繁瑣,vuex使用「惟一數據源」進行管理,全部的組件直接從vuex獲取數據便可;在使用原生vue時,若是多個視圖共享同一個狀態的話,當一個視圖修改這一狀態,咱們須要同步其餘視圖的狀態,而vuex中的狀態值都是響應式的,狀態值一旦被修改,全部引用該值的地方就會自動更新。vue
經過一個商品列表的栗子來演示一下Vuex的用法,首先看一下使用props進行傳參的用法,添加兩個組件:ProductListOne和ProductListTwe,兩個組件都展現商品的名字和價格,組件代碼以下:vuex
<!-----------------------------App.vue---------------------------------> <template> <div id="app"> <production-list-one :products="products"></production-list-one> <production-list-twe :products="products"></production-list-twe> </div> </template> <script> import ProductListOne from "./components/ProductListOne.vue"; import ProductListTwe from "./components/ProductListTwe.vue"; export default { name: "app", components: { "production-list-one": ProductListOne, "production-list-twe": ProductListTwe }, data() { return { products: [ { id: 1, name: "電視", price: 2000 }, { id: 2, name: "電腦", price: 5000 }, { id: 3, name: "空調", price: 1500 }, { id: 4, name: "冰箱", price: 3000 } ] }; } }; </script> <!-----------------------------ProductListOne.vue---------------------------------> <template> <div id="production-list-one"> <h4>Product list one </h4> <ul> <li v-for="product in products" v-bind:key="product.id"> <span class=name>{{product.name}}</span> <span class=price>¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { props:["products"], data() { return { }; } }; </script> <!-----------------------------ProductListTwe.vue---------------------------------> <template> <div id="product-list-twe"> <h4>Product list twe</h4> <ul> <li v-for="product in products" v-bind:key="product.id"> <span class="name">{{product.name}}</span> <span class="price">¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { props: ["products"], data() { return {}; } } </script>
運行程序後,顯示以下:npm
前邊父組件App.vue中的數據products經過props傳到這兩個組件中,如今咱們使用vuex來保存products,首先使用 cnpm install vuex --save 添加vuex包,而後添加一個store.js文件來保持數據,該文件代碼以下,其中store對象做爲「惟一數據源」而存在,因此每一個應用都僅僅包含一個store實例,在store對象中state用於保存原始數據:app
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { products: [ {id: 1,name: "洗衣機",price: 2000}, {id: 2,name: "電腦",price: 5000}, {id: 3,name: "空調",price: 1500}, {id: 4,name: "冰箱",price: 3000} ] } })
接着在main.js中引入vuex,以下:異步
import Vue from 'vue' import App from './App.vue' import {store} from './store/store.js' new Vue({ store:store, el: '#app', render: h => h(App) })
而後修改組件以下:this
<!-----------------------------App.vue---------------------------------> <template> <div id="app"> <production-list-one></production-list-one> <production-list-twe></production-list-twe> </div> </template> <script> import ProductListOne from "./components/ProductListOne.vue"; import ProductListTwe from "./components/ProductListTwe.vue"; export default { name: "app", components: { "production-list-one": ProductListOne, "production-list-twe": ProductListTwe }, data() {return {};} }; </script> <!-----------------------------ProductListOne.vue---------------------------------> <template> <div id="production-list-one"> <h4>Product list one </h4> <ul> <li v-for="product in saleProducts1" v-bind:key="product.id"> <span class=name>{{product.name}}</span> <span class=price>¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { computed:{ saleProducts1(){ return this.$store.state.products } } }; </script> <!-----------------------------ProductListTwe.vue---------------------------------> <template> <div id="product-list-twe"> <h4>Product list twe</h4> <ul> <li v-for="product in salesProducts2" v-bind:key="product.id"> <span class="name">{{product.name}}</span> <span class="price">¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { computed:{ salesProducts2(){ return this.$store.state.products } } }; </script>
運行程序後,顯示和使用props傳值的效果同樣,兩個列表組件的數據源都不在經過props獲取,而是經過 this.$store.state.products 從vuex中獲取,到這裏咱們已經完成了vuex的簡單使用。spa
在vuex中state屬性保存的是原始狀態,有時候咱們須要展現的數據是一些派生狀態,就是是對state中的原始數據作必定的邏輯處理後數據,如咱們展現的商品列表的價格是打八折後的價格。對應這種需求,咱們能夠先在組件中使用this.$store.state.xxx獲取到原始數據而後在組件中直接寫邏輯代碼進行處理,可是若是邏輯處理獲取的數據在多個組件中都要使用的話,這就須要在每一個組件中都重複一遍邏輯代碼。爲了減小代碼冗餘,咱們可使用getter屬性把"八折"這個共享的邏輯提取出來,實現很簡單,直接看代碼吧調試
修改store.js,代碼以下:code
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { products: [ {id: 1,name: "洗衣機",price: 2000}, {id: 2,name: "電腦",price: 5000}, {id: 3,name: "空調",price: 1500}, {id: 4,name: "冰箱",price: 3000} ] }, getters: { saleProducts(state) { var saleProducts=state.products.map((product)=>{ return {id:product.id,name:`產品${product.id}:${product.name} `,price:product.price*0.8} }) return saleProducts; } } })
修改組件代碼以下:component
<!-----------------------------App.vue---------------------------------> <template> <div id="app"> <production-list-one></production-list-one> <production-list-twe></production-list-twe> </div> </template> <script> import ProductListOne from "./components/ProductListOne.vue"; import ProductListTwe from "./components/ProductListTwe.vue"; export default { name: "app", components: { "production-list-one": ProductListOne, "production-list-twe": ProductListTwe }, data() {return {};} }; </script> <!-----------------------------ProductListOne.vue---------------------------------> <template> <div id="production-list-one"> <h4>Product list one </h4> <ul> <li v-for="product in saleProducts1" v-bind:key="product.id"> <span class=name>{{product.name}}</span> <span class=price>¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { computed:{ saleProducts1(){ return this.$store.getters.saleProducts } }, }; </script> <!-----------------------------ProductListTwe.vue---------------------------------> <template> <div id="product-list-twe"> <h4>Product list twe</h4> <ul> <li v-for="product in saleProducts2" v-bind:key="product.id"> <span class="name">{{product.name}}</span> <span class="price">¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { computed:{ saleProducts2(){ return this.$store.getters.saleProducts } } }; </script>
咱們能夠經過 this.$state.getters.xxx 去獲取getters中的數據,運行程序後結果以下:
上邊的state用於存儲和獲取原始值,getters負責封裝公共邏輯,獲取計算後的狀態,二者都是獲取數據時使用的。當咱們想修改store中的狀態怎麼實現呢?提交mutations是更改vuex的stroe中狀態的惟一方法。看一個需求:添加一個降價按鈕,每次點擊都會降價指定的金額。
首先修改store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { products: [ {id: 1,name: "洗衣機",price: 2000}, {id: 2,name: "電腦",price: 5000}, {id: 3,name: "空調",price: 1500}, {id: 4,name: "冰箱",price: 3000} ] }, getters: { saleProducts(state) { var saleProducts=state.products.map((product)=>{ return {id:product.id,name:`產品${product.id}:${product.name} `,price:product.price*0.8} }) return saleProducts; } }, mutations:{ reducePrice:function(state,num){ state.products.forEach(proudcts=>proudcts.price-=num) } } })
修改組件以下:
<!-----------------------------App.vue---------------------------------> <template> <div id="app"> <production-list-one></production-list-one> <production-list-twe></production-list-twe> </div> </template> <script> import ProductListOne from "./components/ProductListOne.vue"; import ProductListTwe from "./components/ProductListTwe.vue"; export default { name: "app", components: { "production-list-one": ProductListOne, "production-list-twe": ProductListTwe }, data() {return {};} }; </script> <!-----------------------------ProductListOne.vue---------------------------------> <template> <div id="production-list-one"> <h4>Product list one </h4> <ul> <li v-for="product in saleProducts1" v-bind:key="product.id"> <span class=name>{{product.name}}</span> <span class=price>¥{{product.price}}</span> </li> </ul> <button @click="reducePrice(10)">商品降價</button> </div> </template> <script> export default { //使用vuex中的getters computed:{ saleProducts1(){ return this.$store.getters.saleProducts } }, //使用mutations降價 methods:{ reducePrice:function(num){ this.$store.commit('reducePrice',num) } } }; </script> <!-----------------------------ProductListOne.vue---------------------------------> <template> <div id="product-list-twe"> <h4>Product list twe</h4> <ul> <li v-for="product in saleProducts2" v-bind:key="product.id"> <span class="name">{{product.name}}</span> <span class="price">¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { computed:{ saleProducts2(){return this.$store.getters.saleProducts} } }; </script>
刷新頁面,效果以下:
使用mutations咱們能夠直接修改store中的原始值,可是官方不推薦這種作法,官方推薦須要修改store中的值時,咱們首先要提交一個action,在action中提交mutation來修改狀態值。這種方式方便咱們進行調試,同時容易實現異步操做。仍是使用降價的栗子,咱們點擊按鈕2秒後實現降價。action的參數是一個和store具備相同方法和屬性的context對象,咱們能夠經過 context.state 和 context.getters 來獲取state和getters,也可使用 context.commit(mutation,payload) 來提交一個mutation,使用首先修改store.js:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { products: [ {id: 1,name: "洗衣機",price: 2000}, {id: 2,name: "電腦",price: 5000}, {id: 3,name: "空調",price: 1500}, {id: 4,name: "冰箱",price: 3000} ] }, getters: { saleProducts(state) { var saleProducts=state.products.map((product)=>{ return {id:product.id,name:`產品${product.id}:${product.name} `,price:product.price*0.8} }) return saleProducts; } }, mutations:{ reducePrice:function(state,num){ state.products.forEach(proudcts=>proudcts.price-=num) } },
//兩秒後在提交reducePrice,context是上下文至關於組件中的this.$store actions:{ reducePriceAction:(context,num)=>{ setTimeout(function(){ context.commit("reducePrice",num) },2000) } } })
修改組件以下:
<!-----------------------------App.vue---------------------------------> <template> <div id="app"> <production-list-one></production-list-one> <production-list-twe></production-list-twe> </div> </template> <script> import ProductListOne from "./components/ProductListOne.vue"; import ProductListTwe from "./components/ProductListTwe.vue"; export default { name: "app", components: { "production-list-one": ProductListOne, "production-list-twe": ProductListTwe }, data() {return {};} }; </script> <!-----------------------------ProductListOne.vue---------------------------------> <template> <div id="production-list-one"> <h4>Product list one</h4> <ul> <li v-for="product in saleProducts1" v-bind:key="product.id"> <span class="name">{{product.name}}</span> <span class="price">¥{{product.price}}</span> </li> </ul> <button @click="reducePrice(10)">商品降價</button> </div> </template> <script> export default { //使用vuex中的getters computed: { saleProducts1() { return this.$store.getters.saleProducts; } }, //使用action降價,每次降價20元 methods: { reducePrice: function(num) { this.$store.dispatch("reducePriceAction", num); } } }; </script> <!-----------------------------ProductListTwe.vue---------------------------------> <template> <div id="product-list-twe"> <h4>Product list twe</h4> <ul> <li v-for="product in saleProducts2" v-bind:key="product.id"> <span class="name">{{product.name}}</span> <span class="price">¥{{product.price}}</span> </li> </ul> </div> </template> <script> export default { computed:{ saleProducts2(){ return this.$store.getters.saleProducts } } }; </script>
實現效果以下:
本文是vuex的簡單入門筆記,更高的特性在之後開發中遇到了在作研究,若是文中有錯誤但願你們能夠指出,我會及時改正。