VUEX的使用方法

247 阅读2分钟

jq.png

jq2.png


##vuex

可以用于解决不同组件之间数据的共享问题。

可以把多个页面需要的属性存放到vuex当中。

 

##vuex 五个核心属性

state【在computed里面调用】

state 可以理解为组件中的data,但是组件当中的data是一个局部的数据仓库,而state是一个全局的数据仓库,只要数据存放在state里面,任何组件都可以访问它的数据。

一般我们都是用计算属性来接受vuex里面的数据;

通过 this.$store.state.carLi st 来获取state里面的数据。

      

   <template>
    <div>
        //这是商品详情页面
        <ul>
            <li v-for="(item,index) in list" :key="index">
               ID:{{item.id}}

               名称:{{item.name}}

               数量:{{item.num}}

               价格:{{item.price}}
            </li>
        </ul>
    </div>
  </template>
   
  list(){
            return this.$store.state.list;
        }

    },

    created() {
       console.log(this.$store.state.carList);
    },

mutations【在methods里面调用】

mutations 可以理解为全局的方法,跟组件当中的methods类似;定义在组件当中的methods是局部方法;定义在mutations里面的方法可以被任何组件所访问。

如果想要修改state当中的数据,需要在mutations里面修改,这是vuex的一个规范。

下面是一个不规范的示例:

methods:{ **//** **在** **methods** **里面提交** **mutations** **里面的方法**

    change(){

        this.$store.state.name = '李四'; //可以,但是不推荐

    }

}

可以直接修改全局数据仓库里面的属性,修改之后的属性会同步传递到其他组件中去,但是不推荐用这种方式去直接修改数据仓库里面的属性

规范示例:

//推荐用mutations里面的方法去进行修改


      this.$store.commit("upts"); //不穿值

      this.$store.commit("upts","赵六"); //传递值(赵六)给mutations

      this.$store.commit("upts",{username:"王九",age:"13"}) //传递多个值,要组合成对象或者数组的形式,因为载荷只能接受一个参数

actions【在methods里面调用】

可以理解为全局的方法,跟组件当中的methods类似。它跟mutations的区别是:mutations里面写的方法是一个同步方法,而actions里面写的方法可以是同步,也可以是异步。

通过actions解决了mutations异步操作导致的VUE调试工具与页面所展示的数据不一致的问题。如果在mutations里面书写异步操作,调试工具将不能检测到数据的变化。

正确做法:在actions里面执行mutations里面的同步方法。

通过 this.$store.dispatch("changeSync",val) 来调用actions里面的方法。val是传递给actions的参数,dispatch叫做分发;


actions:{ 

      //1、如果在mutations里面书写异步操作,调试工具将不能检测到数据的变化

    changeSync(context,val){//context是上下文对象,也可以理解为store;context对象里面可以获取到getters或者state的数据,或者执行mutations里面的方法

      // console.log(context);

 

      //2、此时虽然异步操作写在了actions里面,但是调试工具依然不能检测到数据的变化

      // setTimeout(function(){

      //   let item = context.state.list.find(ete => ete.id == val.id); //find()方法是javascript内置方法

      //   item.num--;

      //   if(context.state.carList.some(ete => ete.id == val.id)){

      //       let carItem = context.state.carList.find(ete => ete.id == val.id);

      //       carItem.num++;

      //   }else{

      //       let obj = {

      //         id: val.id,

      //         name: val.name,

      //         num: 1,

      //         price: val.price ,

      //         isChecked: false,

      //       };

      //       context.state.carList.push(obj);

      //   }

      // },1000)

 

 

      **//** **正确做法:在** **actions** **里面提交** **mutations** **里面的方法**

      setTimeout(() => {

        context.commit("change",val);

      },1000);

 

    }

  },

 

<template>

    <div>

        这是商品详情页面

        <ul>

            <li v-for="(item,index) in list" :key="index">

               ID:{{item.id}}

               名称:{{item.name}}

               数量:{{item.num}}

               价格:{{item.price}}

               <button @click="add(item)" :disabled="item.num == 0">添加</button> <!--当商品数量为0时禁用-->

               <button @click="addSync(item)">异步添加</button>

            </li>

        </ul>

    </div>

</template>

<script>

export default {

    computed: {//一般我们都是用计算属性来接受vuex里面的数据

        list(){

            return this.$store.state.list;

        }

    },

    created() {

       console.log(this.$store.state.carList);

    },

    methods: { **//** **在** **methods** **里面调用** **actions** **里面的方法**

        add(val){//执行mutations里面的change方法,来改变state的数据

            this.$store.commit("change",val); //val是传递给mutations的参数

        },

        addSync(val){//通过this.$store.dispatch("changeSync")来调用actions里面的方法

            this.$store.dispatch("changeSync",val); ////val是传递给actions的参数

        },

    },

};

</script>
<style scoped lang="scss"></style>

 

getters【在computed里面调用】

类似与computed,用于监听vuex里state的数据变化,用法跟计算属性的用法一致

computed: {

        list(){

            return this.$store.state.carList;

        },

        getPrice(){

            return this.$store.getters.total;

        },

        // isAllchecked(){

        //     return this.$store.getters.isAllchecked;

        // },

        

        //要更改计算属性的值,一定要写成对象形式

        isAllchecked:{

            get(){

                return this.$store.getters.isAllchecked;

            },

            set(val){

                this.$store.commit("uptChecked",val);

            }

        },

 

    },

 

 

 

 

 

 

modules

将store文件夹中的index.js分模块(例如:和登陆有关的数据、方法等就放在login.js中)。

那么如何在其他组件引用modules里面分模块的数据呢?

首先要在store文件夹的index.js中引入它:

store/index.js


import login from './modules/login.js' //引入login.js

import num from './modules/num.js' //引入num.js

import rmb from './modules/myToRMB.js' //引入myToRMB.js

export default new Vuex.Store({

  modules:{

    moduleA: login,

    moduleB: num,

    moduleC: rmb,

  },

  state:{},

  mutations:{},

  actions:{},

  getters:{},

})

 

如何调用modules模块里面的state、mutations、actions、getters

分为两种方式:

1. 用普通方法调用

2. 用vuex辅助函数调用

  • 普通方法调用

state

this.$store.state.moduleA.username // 在调用的时候加上了模块名称

mutations

this.$store.commit("uptUserName") // 调用的时候没有加上对应的模块名称

getters

this.$store.getters["moudleRmb/rmb"]

actions

this.$store.dispatch("moduleB/increaseSync");

 

namespaced: true

代表开启命名空间.  默认获取state里面的数据时,前面要加上模块名称;而mutations、actions、getters不用加模块名称,但是当加上命名空间之后,必须要加上相对应的模块名称。

如果没有开启命名空间,会发生什么?

this.$ store.commit("uptNum ") // 执行此方法时,login.js和num.js里面两个同名的uptNum方法都会执行

2) 用vuex辅助函数调用

###mapState

1. 使用辅助函数获取state里面的数据

注意点:

数组的方式不行:...mapState(["listModule/carList","num"])

对象字符串的方式不行:...mapState({list:"listModule/carList"})

 

正确的做法:要用函数形式获取模块state里面的数据

...mapState({

list:function(state){

return state.listModule.carList;

}

}),

###mapGetters

2. 使用辅助函数获取getters里面的数据

...mapGetters({allChecked:"listModule/isAllChecked"})  

###mapMutations

3. 使用辅助函数获取mutations里面的数据

methods:{

...mapMutations({

decs:"listModule/dec"

})

}

###mapActions

4. 使用辅助函数获取mapActions里面的数据

...mapActions({

inc:"listModule/syncAdd"

})

modules/num.js


**var num = {**

**namespaced: true, //** **代表开启命名空间** **.** **默认获取** **state** **里面的数据时,前面要加上模块名称** **,** **而** **mutations** **、** **actions** **、** **getters** **不用加模块名称,但是当加上命名空间之后,必须要加上相对应的模块名称**

**state: {**

**num: 1 //this.$store.state.moduleA.num**

**},**

**actions: {**

**increaseSync(context){//this.$store.dispatch("moduleB/increaseSync")**

**console.log(context);**

**//** **在异步操作里面调用同步操作**

**setTimeout(()=>{**

**context.commit("increase")**

**},1000)**

**},**

**},**

**mutations: {**

**uptNum(state){ //this.$store.commit("moduleB/uptNum")**

**state.num += 4**

**},**

**increase(state){**

**state.num++;**

**},**

**decrease(state){**

**state.num--;**

**},**

**},**

**getters: {}**

**}**

**export default num;**

<template>

  <div class="about">

    <h1>辅助函数</h1>

    <p>{{num}} {{name}}</p>

    <p>这里是当前组件的area:{{area}}</p>

    <p>这里是vuex里面的area:{{areas}}</p>

    <p>{{area1}}</p>

    <p>{{area2}}</p>

    <p>

      请输入美元:

      <input type="text" v-model="my" @input="changes">

    </p>

    <p>转换之后的结果:{{rmb}}</p>

    <p>moduleA里面的数据:{{moduleANum}}</p>

    <p>moduleB里面的数据:{{moduleBNum}}</p>

    <button @click="upts">点击</button>

  </div>

</template>

<script>

//我们用vuex的辅助函数时,首先要先引入它

import { mapState,mapMutations } from "vuex";

 

 

export default{

  methods:{

    // ...mapMutations({

    //   uptMy : "uptMy"

    // }),

    changes(){

      //  this.uptMy(this.my);

      this.$store.commit("moduleRmb/uptMy",this.my);

    },

    upts(){

      // this.$store.commit("uptNum") //**这里没有开启命名空间时,执行的方式,此时** **login.js** **和** **num.js** **里面两个同名的** **uptNum** **方法都会执行**

      this.$store.commit("moduleA/uptNum") //开启命名空间之后,可以用这种方式只执行模块A也就是login.js里面的uptNum

    }

  },

  data(){

    return {

      area:"郑州",

      my: 10,

    }

  },

  computed:{

    moduleANum(){

      return this.$store.state.moduleA.num;

    },

    moduleBNum(){

      return this.$store.state.moduleB.num;

    },

    rmb(){

      return this.$store.getters["moduleRmb/rmb"];

    },

 

    // num(){

    //   return this.$store.state.num;

    // },

 

 

    //等价于上面的num方法

    ...mapState(["num","name"]), //当然它把name数据也搞过来了,而上面没有

 

 

    //**vuex** **里面的数据和当前组件数据同名时,如果想要获得** **vuex** **里面的数据得要用对象的形式给它取一个别名**

    ...mapState({

      areas:"area" //字符串方式获取state里面的数据

    }),

 

 

  //函数方式获取state里面的数据

  //通过函数形式的好处是:可以将本地组件的数据和vuex里面的数据结合起来用

    area1:function(state){

      if(!this.area){//如果本地组件不存在area数据,则返回vuex里面的area,否则返回本地组件里面的数据

        return state.area;

      }else{

        return this.area;

      }

    },

 

 

    area2:(state) => {

      console.log(this); //undefined

      return state.area;

    }

 

  },

}

</script>

 

vuex 辅助函数(四个),帮助我们节省代码的语法糖:

  • mapState
  • mapGetters
  • mapMutations
  • mapActions**  

mapState 和mapGetters放在computed计算属性里面;

mapActions 和mapMutations放在methods方法里面;

如何用呢?

home.vue


<script>

**//** **我们用** **vuex** **的辅助函数时,首先要先引入它**

import {mapState,mapActions,mapMutations,mapGetters} from "vuex";

 

export default{

  methods:{

    **// ...mapMutations({**

**//   uptMy : "uptMy" //** **把** **mutations** **里面的方法搞过来**

**// }),**

    changes(){

      **//  this.uptMy(this.my); //** **调用【** **this.my** **是传递过去的参数】**

      this.$store.commit("moduleRmb/uptMy",this.my);

    },

  },

  data(){

    return {

      area:"郑州",

      my: 10,

    }

  },

  computed:{

    **// ...mapGetters({**

**//   rmb: "rmb"**

**// }),**

 

    // num(){

    //   return this.$store.state.num;

    // },

 

 

    //等价于上面的num方法

    ...mapState(["num","name"]),

 

 

    //vuex里面的数据和当前组件数据同名时,如果想要获得vuex里面的数据得要用对象的形式给它取一个别名

    ...mapState({

      areas:"area" //字符串方式获取state里面的数据

    }),

 

  },

}

</script>

 

<template>

  <div class="home">

    <!-- <button @click="incSync">异步+</button>-->

    <button @click="increaseSync">异步+</button>

  </div>

</template>

 

 

<script>

import { mapActions } from 'vuex'

export default {

  name: 'Home',

  methods:{

    **...mapActions({**

**increaseSync : "increaseSync"**

**}),**

       **incSync(){**

**this.$store.dispatch("increaseSync");**

**},**

  },

}

</script>

 

import Vue from 'vue'

import Vuex from 'vuex'

 

 

Vue.use(Vuex)

 

 

import login from './modules/login.js' //引入login.js

import num from './modules/num.js' //引入num.js

import rmb from './modules/myToRMB.js'

 

 

export default new Vuex.Store({

  modules: {//注册模块

    moduleA: login,

    moduleB: num,

    moduleRmb: rmb,

  },

  state: {

    num: 1,

    area: "北京",

    name: "张三",

    my: ""

  },

  mutations: {

    uptMy(state,val){

      state.my = val;

    },

    /**

     *

     * @param {*} state

     * @param {*} val

     * 有两种调用方式

     * 1.this.$store.commit("uptUsername")

     * 2.辅助函数:mapMutations

     */

    uptUsername(state,val){

        state.username = val

    },

  },

 

 

  actions: {

    increaseSync(context){

      console.log(context);

      //在异步操作里面调用同步操作

      setTimeout(()=>{

        context.commit("increase")

      },1000)

    },

  },

 

 

  getters: {

    rmb(state){

      return state.my*7.0905;

    }

  },
 

})

 ```

 

vuex的缺陷:

当刷新页面之后,存储在vuex,state当中的数据就重新初始化了。

如果想要在vuex长久的存储数据,需要vuex与本地存储结合使用