zoukankan      html  css  js  c++  java
  • 深度解析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

     

     
     

           

       

  • 相关阅读:
    #C++初学记录(sort函数)
    #C++初学记录(贪心算法#结构体#贪心算法)
    #C++初学记录(初识汉诺塔)
    vuex中使用多模块时,如果不同模块中action有名字冲突该如何解决
    vue中二次封装别人组件,动态传属性使用v-bind="$attrs" 和 v-on="$listeners"
    在vue.config.js项目中配置proxy解决跨域问题
    Vue里报错:Maximum call stack size exceeded
    git报错:pre-commit hook failed (add --no-verify to bypass)
    十大排序算法,用JS写出来
    基数排序(JS代码)
  • 原文地址:https://www.cnblogs.com/hgdzjp/p/10136119.html
Copyright © 2011-2022 走看看