Vuex实现状态管理

Vuex使用总结

1 Vuex简介

  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

state

   前边父组件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

getters

  在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中的数据,运行程序后结果以下:

 

 

 mutations

  上边的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>

  刷新页面,效果以下:

actions

  使用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的简单入门笔记,更高的特性在之后开发中遇到了在作研究,若是文中有错误但愿你们能够指出,我会及时改正。

相关文章
相关标签/搜索