深度解析vuex

1、什么是vuex?

      vuex 是一个专为 Vue.js 应用程序开发的状态管理模式(通俗一点的说Vuex就是存储数据的工具,类似于cookie、sessionStorage、localStorage)。

2、vuex和cookie、sessionStorage、localStorage的区别:

      cookie、sessionStorage、localStorage是浏览器存储,每当页面刷新时数据依然存在(在过期时间内),而vuex在页面刷新时存储的数据会丢失。

3、vuex一般用于大型的SPA应用,否则最好不要使用vuex。

4、基本用法:

     npm安装: npm install vuex --save

    新建一个store文件夹,在该文件夹下新建一个index.js文件,机构目录入下图:

                  

    Vuex有以下几个选项:state、mutations、actions、getters、module

   在该index.js文件里:

import Vue from 'vue';  //引入vue
import Vuex from 'vuex';//引入vuex
Vue.use(Vuex);
//新建一个store仓库, state 是存储数据的 const store
=new Vuex.Store({ state:{ count:12 } }) export default store;

     4.1、读取数据: 在任何组件里可以通过$store.state.count来读取数据

   

 <p>{{$store.state.count}}</p>

 或者通过计算属性进行处理

   

<template>
  <div class="hello">
        <!--直接读取-->
        <p>{{$store.state.count}}</p> 
         <!--通过计算属性获取-->
        <p>{{count}}</p>
  </div>
</template>

<script>
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
      count(){
          return this.$store.state.count;
      }
  }

}
</script>
<style>

</style>

结果如下图:

    4.2、修改数据:

   在组件内,来自store的数据只能读取,不能手动修改,改变store中数据的唯一途径就是显式的提交mutations。

   在以下demo中实现加1和减一的效果:

    

const store=new Vuex.Store({
    //选项一:state用来存储数据的
    state:{
        count:12
    },
    //选项二:mutations用来修改state中的数据的
    mutations:{
        increament(state){
            console.log(state);
            //以上打印的是 count:12 ,在这里可以获取到state中的count数据,所以可以在这里直接进行修改
            state.count ++;
        },
        decrease(state){
       console.log(state); state.count
--; } } })

         加1的结果:

            

 

      减1的结果:

      

 

   以上结果显式通过mutations已经成功的修改了state中的数据。

   此外mutations还可以接受第二个参数:

   修改之前的代码:

 methods:{
//自定义一个num传给mutations addOne(){ let num
=10; this.$store.commit('increament',num); }, reduceOne(){ let num=5; this.$store.commit('decrease',num); } }
mutations:{
        increament(state,num){
            console.log(num); //打印的是10
            state.count+=num;
        },
        decrease(state,num){
            console.log(num); //打印的是5
            state.count-=num;
        }
    }

 此时,加10和减5修改成功。

  5、高级用法:

     Vuex除了state、mutations外还有getters、actions、modules选项

       5.1、getters:

         “Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算”

   

      demo:过滤出偶数

const store=new Vuex.Store({
    //选项一:state用来存储数据的
    state:{
        count:[1,2,3,4,5,6,7,8,9,10]
    },
    //选项二:mutations用来修改state中的数据的
    mutations:{
        increament(state,num){
            state.count+=num;
        },
        decrease(state,num){
            state.count-=num;
        }
    },
    //选项三:getters相当于计算属性
    getters:{
        filterData(state){
            console.log(state)
            //过滤出偶数
            return state.count.filter(item=>item%2==0)
        }
    }
})
<template>
  <div class="hello">
         <!--通过计算属性获取-->
        <p v-for="item in count">{{item}}</p>
  </div>
</template>

<script>
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
      count(){
          return this.$store.getters.filterData;
      }
  }
}
</script>
<style>

</style>

结果如下:

 

   5.2、actions:异步操作state数据,一般用于后台请求数据。

           mutation里尽量不要异步操作数据,如果异步操作数据了,组件在commit后数据不能立即改变,而且也不知道什么会改变,actions就是专门处理异步操作的。

           demo:3s后原数据加20

      

<template>
  <div class="hello">
                     异步数据:{{count}}
        <button @click="asyncClick">异步处理</button>
  </div>
</template>

<script>
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
      list(){
          return this.$store.getters.filterData;
      },
      count(){
          return this.$store.state.count;
      }
  },
  methods:{
      asyncClick(){
          //这里随便传过去一个数字20
          this.$store.dispatch('asyncIncreament',20).then(()=>{
              //修改成功的回调
              console.log(this.$store.state.count); //32
          });
      }
  }
}
</script>
<style>

</style>

  store

  

const store=new Vuex.Store({
    //选项一:state用来存储数据的
    state:{
        list:[1,2,3,4,5,6,7,8,9,10],
        count:12,
    },
    //选项二:mutations用来修改state中的数据的
    mutations:{
        increament(state,num){
            state.count+=num;
        },
        decrease(state,num){
            state.count-=num;
        }
    },
    //选项三:getters相当于计算属性
    getters:{
        filterData(state){
            console.log(state)
            //过滤出偶数
            return state.list.filter(item=>item%2==0)
        }
    },
    //选项四:actions实现异步操作
    actions:{
        asyncIncreament(content,num){
            return new Promise(resolve=>{
                setTimeout(()=>{
                    content.commit('increament',num);
                    resolve();
                },3000)
            })
        }
    }
})
export default store;

结果如下:

   点击 “异步处理”按钮3s后页面的数据由原来的12变为32,修改成功后控制台打印结果32

   

5.3、module: 模块化处理

    module是用来将store分割到不同的模块,当你的项目足够大时,store里的state、getters、mutations、actions会非常多,都放在mian.js里不是很友好,使用modules可以把它们写到不同的文件中。每个module拥有自己的state、getters、mutations、         actions,而且可以多层嵌套。

  demo:

         目录结构:

         

<template>
  <div class="hello">        
        <button @click="asyncClick">异步处理</button>
       <p> 模块A的数据:{{countOne}}</p>
       <p> 模块B的数据:{{countTwo}}</p>
  </div>
</template>

<script>
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
      countOne(){
            //获取模块a的state数据
            return this.$store.state.a.countOne;
      },
      countTwo(){
          //获取模块b的state数据
            return this.$store.state.b.countTwo;
      }
  },
  methods:{
      asyncClick(){
          //异步处理模块a的数据
        this.$store.dispatch('asyncIncreamenta',30);
        //异步处理模块b的数据
        this.$store.dispatch('asyncIncreamentb',30);
      }
  }
}
</script>

 

   模块a:

     

//模块A
export default{
    //选项一:state用来存储数据的
    state:{
        list:[1,2,3,4,5,6,7,8,9,10],
        countOne:12,
    },
    //选项二:mutations用来修改state中的数据的
    mutations:{
        increamentOne(state,num){
            state.countOne+=num;
        },
        decreaseOne(state,num){
            state.countOne-=num;
        }
    },
    //选项三:getters相当于计算属性
    getters:{
        filterDataOne(countOne){
            //过滤出偶数
            return countOne.list.filter(item=>item%2==0)
        }
    },
    //选项四:actions实现异步操作
    actions:{
        asyncIncreamenta(content,num){
            return new Promise(resolve=>{
                setTimeout(()=>{
                    content.commit('increamentOne',num);
                    resolve();
                },1000)
            })
        }
    }
}

模块b:

//模块B
export default{
        //选项一:state用来存储数据的
    state:{
        list:[1,2,3,4,5,6,7,8,9,10],
        countTwo:52,
    },
    //选项二:mutations用来修改state中的数据的
    mutations:{
        increament(state,num){
            state.countTwo+=num;
        },
        decrease(state,num){
            state.count-=num;
        }
    },
    //选项三:getters相当于计算属性
    getters:{
        filterData(state){
            //过滤出偶数
            return state.list.filter(item=>item%2==0)
        }
    },
    //选项四:actions实现异步操作
    actions:{
        asyncIncreamentb(content,num){
            return new Promise(resolve=>{
                setTimeout(()=>{
                    content.commit('increament',num);
                    resolve();
                },1000)
            })
        }
    }
}

 store下的index.js:

   

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import moduleA from './moduleA.js'
import moduleB from './moduleB.js'
const store=new Vuex.Store({
   modules:{
         a:moduleA,
         b:moduleB
   }
})
export default store;

 点击“异步处理”按钮 1s后模块a和模块b的state的数据发生了改变。

6、mapState 、mapGetters、mapActions:

 6.1、mapState 
通过this.$store.state.count 获取store中的数据写法很长,所以为了简化写法可以使用 mapState 进行操作,

<template>
  <div class="hello">        
        <button @click="asyncClick">异步处理</button>
       <p> 模块A的数据:{{countOne}}</p> 
       <p> 模块B的数据:{{countTwo}}</p>
        <p> mapState获取模块A的数据:{{messageOne}}</p>
        <p> mapState获取模块B的数据:{{messageTwo}}</p>
  </div>
</template>

<script>
    //首先引入mapState,mapGetters,mapActions
import {mapState,mapGetters,mapActions} from 'vuex'
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
    countOne(){
          //获取模块a的state数据
            return this.$store.state.a.countOne;
    },
    countTwo(){
        //获取模块b的state数据
            return this.$store.state.b.countTwo;
    },
      //这里的3个点表示扩展运算符(ES6的知识)
      ...mapState({
                 messageOne: state => state.a.countOne,
                 /*
                   相当于:
                    messageOne(){
                        return state.a.countOne;
                    }
                  * */
                 messageTwo: state => state.b.countTwo,
                 
      })
  },
  methods:{
      asyncClick(){
          //异步处理模块a的数据
        this.$store.dispatch('asyncIncreamenta',30);
        //异步处理模块b的数据
        this.$store.dispatch('asyncIncreamentb',30);
      }
  }
}
</script>
<style>

</style>

结果如下:

  

结果显示:通过mapState获取的数据和通过this.$store获取的数据一致。

6.2、mapGetters
<template>
  <div class="hello">        
        <button @click="asyncClick">异步处理</button>
       <p> 模块A的数据:{{countOne}}</p> 
       <p> 模块B的数据:{{countTwo}}</p>
        <!--遍历模块a中的列表-->
        <p>遍历模块a中的列表:</p>
        <p v-for="item in filterDataOne">{{item}}</p>
  </div>
</template>

<script>
    //首先引入mapState,mapGetters,mapActions
import {mapState,mapGetters,mapActions} from 'vuex'
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
    countOne(){
          //获取模块a的state数据
            return this.$store.state.a.countOne;
    },
    countTwo(){
        //获取模块b的state数据
            return this.$store.state.b.countTwo;
    },
      ...mapGetters([
          //模块a中 filterDataOne
            'filterDataOne', 
      ]),
  },
  methods:{
      asyncClick(){
          //异步处理模块a的数据
        this.$store.dispatch('asyncIncreamenta',30);
        //异步处理模块b的数据
        this.$store.dispatch('asyncIncreamentb',30);
      }
  }
}
</script>

结果如下:

 

6.3、mapAction:

  

<template>
  <div class="hello">        
       <!-- <button @click="asyncClick">异步处理</button>-->
       <p> 模块A的数据:{{countOne}}</p> 
       <p> 模块B的数据:{{countTwo}}</p>
        <p> mapState获取模块A的数据:{{messageOne}}</p>
        <p> mapState获取模块B的数据:{{messageTwo}}</p>
        <!--遍历模块a中的列表-->
        <!--<p v-for="item in filterDataOne">{{item}}</p>-->
         <button @click="asyncIncreamenta(100)">mapActions异步处理</button>
  </div>
</template>

<script>
    //首先引入mapState,mapGetters,mapActions
import {mapState,mapGetters,mapActions} from 'vuex'
export default {
   data(){
      return{
          originData:'hello Vue'
      }
  },
  computed:{
    countOne(){
          //获取模块a的state数据
            return this.$store.state.a.countOne;
    },
    countTwo(){
        //获取模块b的state数据
            return this.$store.state.b.countTwo;
    },
      //这里的3个点表示扩展运算符(ES6的知识)
      ...mapState({
                 messageOne: state => state.a.countOne,
                 /*
                   相当于:
                    messageOne(){
                        return state.a.countOne;
                    }
                  * */
                 messageTwo: state => state.b.countTwo,
                 
      }),
      ...mapGetters([
          //模块a中 filterDataOne
            'filterDataOne', 
      ]),
  },
  methods:{
      ...mapActions(['asyncIncreamenta']),
//    asyncClick(){
//        //异步处理模块a的数据
//      this.$store.dispatch('asyncIncreamenta',30);
//      //异步处理模块b的数据
//      this.$store.dispatch('asyncIncreamentb',30);
//    }
  }
}
</script>
<style>

</style>

点击“mapActions”按钮1后结果如下:

模块a的数据增加了100

 

 
 

 

       

 

 

   

posted @ 2018-12-18 17:34  唯美(vmei)  阅读(1042)  评论(0编辑  收藏  举报