美文网首页Vue.js
Vuex简单使用

Vuex简单使用

作者: 叽里咕呱 | 来源:发表于2021-12-23 12:28 被阅读0次

    一、初始化Vuex

    Vuex是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    如果一份数据需要在多个组件中使用,组件间传值又比较复杂,就可以使用vuex托管数据。

    1、安装

    npm install vuex --save
    

    2、导入

    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)
    

    3、创建状态管理对象 store

    state选项:定义状态(状态就是数据)。
    mutations选项:定义修改状态的方法(注意:这里面只能定义同步方法)。

    export default new Vuex.Store({
      // 定义全局状态(状态就是数据)
      state:{
        car:{
            name:'奔驰',
            price:'40W'
        }
      },
      // 定义修改状态的方法
      mutations:{
        //该方法,修改汽车信息
        updateCar(state,val){
            state.car = val
        }
      }
    })
    

    4、注册给Vue

    // 导入当前项目中的全局状态管理对象
    import store from './store'
    new Vue({
      // 在vue实例中使用全局状态管理对象
      store,
      render: h => h(App)
    }).$mount('#app')
    

    5、简单使用

    $store:返回的是当前项目中的全局状态对象。
    commit()方法:用于执行指定的mutations里面的方法。

    (1)获取数据

    在组件中,直接通过$store.state就可以获取到全局状态对象管理的状态数据,直接渲染到页面。

    <div>车辆名称:{{ $store.state.car.name }}</div>
    <div>车辆价格:{{ $store.state.car.price }}</div>
    

    (2)修改数据

    <div>车辆名称:{{ $store.state.car.name }}</div>
    <div>车辆价格:{{ $store.state.car.price }}</div>
    <button @click="updateCar">修改汽车信息</button>
    
    methods: {
      updateCar() {
        this.$store.commit("updateCar", { name: "奔驰", price: "60W" });
      }
    }
    

    二、核心概念

    1、state

    state选项:定义状态(状态就是数据)。

      state: {
        name:'张三'
      }
    

    通过$store.state.数据名使用。

    <div>姓名:{{ $store.state.name }}</div>
    

    2、getters

    getters选项:定义计算属性。方法的参数是状态对象。

      getters:{
        // 方法的第一个参数是全局状态
        nameInfo(state){
          return `我的名字叫${state.name}`
        }
      }
    

    通过$store.getters.属性名使用计算属性。

    <div>{{ $store.getters.nameInfo }}</div>
    

    3、mutations

    mutations选项:定义修改状态的方法(注意:这里的方法一般都是同步方法)。方法的第一个参数是状态对象,第二个参数是新值。

      mutations:{
        // 修改姓名
        updateName(state,val){
          state.name = val
        }
      },
    

    通过commit()方法,调用mutations里面的方法。

    this.$store.commit("updateName", '李四');
    

    4、actions

    actions选项:定义操作状态的方法(这里的方法可以定义异步方法)。
    注意:actions里的方法最好不要直接操作state状态,而是通过调用mutations里面的方法去修改状态。所以,actions直接操作的是mutations。

      state: {
        carAddress:'意大利'
      },
      mutations:{
        //修改汽车的产地
        updateCarAddress(state,val){
          state.carAddress = val
        }
      },
      actions:{
        //修改汽车的产地
        //方法的第一个参数是全局状态管理对象,第二个参数是具体的值
        updateCarAddress(store,val){
          axios.get(val).then(({data})=>{
            // 方式一:这里可以直接修改状态
            // store.state.carAddress = data.address
            // 方式二:通过调用mutations里面的方法修改状态
            store.commit('updateCarAddress',data.address)
          })
        }
      }
    

    通过dispatch()方法,调用actions里面定义的方法。

    this.$store.dispatch('updateCarAddress','data/address.json')
    

    5、modules

    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

    (1)定义模块

    namespaced属性:默认情况下,action、mutation 和 getter 是注册在全局命名空间的。通过设置namespaced属性为true,将action、mutation 和 getter全部注册到私有命名空间中。

    export default {
        namespaced:true,
        // 状态
        state:{
            planeName:'空客404',
            planePrice:'10Y',
            planeAddress:'中国'
        },
        // 计算属性
        getters:{
            planeInfo(state){
                return `飞机名称:${state.planeName},飞机价格:${state.planePrice},飞机产地:${state.planeAddress}`
            }
        },
        // 同步方法
        mutations:{
            updatePlaneName(state,val){
                state.planeName = val
            },
            updatePlanePrice(state,val){
                state.planePrice = val
            }
        },
        // 异步方法
        actions:{
            updatePlanePrice(store,val){
                setTimeout(() => {
                    store.commit('updatePlanePrice',val)
                }, 500);
            }
        }
    }
    

    (2)在全局状态管理对象中导入模块

    // 导入飞机模块
    import plane from './modules/plane.js'
    
    // 创建一个全局状态管理对象并导出
    export default new Vuex.Store({
      // 模块
      modules:{
        // 飞机模块
        plane
      }
    })
    

    (3)使用模块

    ① 获取模块中的state状态

    要从私有模块中获取数据,方式是:$store.state.模块名称.模块的数据

    <div>飞机名称:{{ planeName }}</div>
    
    planeName() {
      return this.$store.state.plane.planeName;
    }
    

    ② 获取模块中的getters计算属性

    要从私有模块中获取计算属性,方式是:$store.getters['模块名/计算属性']

    <div>{{planeInfo}}</div>
    
    planeInfo(){
        return this.$store.getters['plane/planeInfo']
    }
    

    ③ 调用模块中的mutations定义的方法

    调用私有模块里面的mutations定义的方法,方式是:$store.commit('模块名/方法名',新值)

    <button @click="updatePlaneName">修改飞机名称</button>
    
    updatePlaneName(){
      this.$store.commit('plane/updatePlaneName','波音747')
    }
    

    ④ 调用模块中的actions定义的方法

    调用私有模块里面的actions定义的方法,方式是:$store.dispatch('模块名/方法名',新值)

    <button @click="updatePlanePrice">修改飞机价格</button>
    
    updatePlanePrice(){
      this.$store.dispatch('plane/updatePlanePrice','20Y')
    }
    

    三、Vuex使用

    1、计算属性中转

    直接在模板中使用全局状态管理数据,表达式会写的很长。所以可以使用计算属性。

      // getters选项定义计算属性
      getters:{
        carInfo(state){
          return `汽车名称:${state.carName},汽车价格:${state.carPrice},汽车产地:${state.carAddress}`
        }
      }
    
     <!-- 直接在模板中使用全局状态里面的计算属性 -->
     <div>{{$store.getters.carInfo}}</div>
     <div>{{carInfo}}</div>
    
      //计算属性
      computed:{
        // 汽车信息
        carInfo(){
          // 返回全局状态管理里面的计算属性
          return this.$store.getters.carInfo
        }
      }
    

    2、映射函数

    通过映射函数mapState、mapGetters、mapActions、mapMutations,可以将vuex.store中的属性映射到vue实例身上,这样在vue实例中就能访问vuex.store中的属性了,便于操作vuex.store。

    (1)导入映射函数

    // 从vuex中,导入映射函数
    import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
    

    (2)使用映射函数生成计算属性

    如果vuex里面state的数据名称 跟 页面中的计算属性名称相同,就可以使用mapState映射函数,自动生成页面中的计算属性。
    如果vuex里面getters的数据名称 跟 页面中的计算属性名称相同,就可以使用mapGetters映射函数,自动生成页面中的计算属性。
    注意:如果要映射模块里面的state/getters,函数的第一个参数设置为模块的名称。

    <div>汽车名称:{{ carName }}</div>
    <div>汽车价格:{{ carPrice }}</div>
    <div>汽车产地:{{ carAddress }}</div>
    <div>{{ carInfo }}</div>
    <hr/>
    <div>飞机名称:{{ planeName }}</div>
    <div>飞机价格:{{ planePrice }}</div>
    <div>飞机产地:{{ planeAddress }}</div>
    <div>{{ planeInfo }}</div>
    
    computed: {
      // mapState映射state
      ...mapState(["carName", "carPrice", "carAddress"]),
      // mapGetters映射getters
      ...mapGetters(["carInfo"]),
    
      // 映射私有模块里面的数据
      ...mapState('plane',['planeName','planePrice','planeAddress']),
      ...mapGetters('plane',['planeInfo'])
    }
    

    (3)使用映射函数生成方法

    如果定义的方法名跟全局管理对象中mutations里面的方法名相同,并且定义的方法会带有一个参数,通过参数传递数据。满足该规则,就可以使用mapMutations映射函数生成方法。
    如果定义的方法名跟全局管理对象中actions里面的方法名相同,并且定义的方法会带有一个参数,通过参数传递数据。满足该规则,就可以使用mapActions映射函数生成方法。
    注意:如果要映射私有模块中mutations/actions里面的方法,函数的第一个参数设置为模块的名称。

    <button @click="updateCarName('宾利')">修改汽车名称</button>
    <button @click="updateCarPrice('300W')">修改汽车价格</button>
    <button @click="updateCarAddress('data/address.json')">修改汽车产地</button>
    <hr/>
    <button @click="updatePlaneName('波音747')">修改飞机名称</button>
    <button @click="updatePlanePrice('20Y')">修改飞机价格</button>
    
    methods: {
      // 映射全局管理对象中mutations里面的方法
      ...mapMutations(["updateCarName", "updateCarPrice"]),
      // 映射全局管理对象中actions里面的方法
      ...mapActions(["updateCarAddress"]),
    
      // 映射私有模块里面的方法
      ...mapMutations('plane',['updatePlaneName']),
      ...mapActions('plane',['updatePlanePrice'])
    }
    

    3、购物车模块

    import axios from "axios";
    export default {
      namespaced: true,
      state: {
        //商品数组
        goodses: [],
      },
      getters: {
        //总价
        totalPrice(state) {
          return state.goodses.filter((r) => r.ck).map((r) => r.price * r.count).reduce((a, b) => a + b, 0);
        },
        // 是否全选
        isCkAll(state) {
          return state.goodses.length>0 & state.goodses.every((r) => r.ck);
        },
      },
      mutations: {
        // 加载数据的同步方法
        loadGoodses(state, val) {
          state.goodses = val;
        },
        // 设置所有商品的状态
        ckAll(state, val) {
          state.goodses.forEach((r) => {
            r.ck = val;
          });
        },
        // 根据id删除商品
        delGoodsById(state, id) {
          let index = state.goodses.findIndex((r) => r.id == id);
          state.goodses.splice(index, 1);
        },
      },
      actions: {
        // 加载数据的异步方法
        loadGoodses(store, val) {
          axios.get(val).then(({ data }) => {
            store.commit("loadGoodses", data);
          });
        },
        // 设置所有商品的状态
        ckAll(store, val) {
          store.commit("ckAll", val);
        },
        // 根据id删除商品
        delGoodsById(store, id) {
            store.commit("delGoodsById", id);
        },
      },
    };
    
    <template>
      <div class="shopcart">
        <h4>购物车</h4>
        <table>
          <thead>
            <tr>
              <th>
                <input type="checkbox" v-model="isCkAll" />
              </th>
              <th>名称</th>
              <th>图片</th>
              <th>单价</th>
              <th>数量</th>
              <th>小计</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="item in goodses" :key="item.id">
              <td>
                <input type="checkbox" v-model="item.ck" />
              </td>
              <td>{{ item.name }}</td>
              <td>
                <img :src="item.img" />
              </td>
              <td>{{ item.price }}</td>
              <td>
                <button @click="item.count--" :disabled="item.count === 1">
                  -
                </button>
                <input type="text" v-model="item.count" />
                <button @click="item.count++" :disabled="item.count === 10">
                  +
                </button>
              </td>
              <td>{{ item.price * item.count }}</td>
              <td>
                <button @click="delGoodsById(item.id)">删除</button>
              </td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td colspan="7">
                <span>总价:</span>
                <span>{{ totalPrice }}</span>
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
    </template>
    <script>
    import { mapState, mapGetters, mapActions } from "vuex";
    export default {
      name: "Shopcart",
      computed: {
        ...mapState("shopcart", ["goodses"]),
        ...mapGetters("shopcart", ["totalPrice"]),
        // 定义可以修改的计算属性
        isCkAll: {
          set(val) {
            this.ckAll(val);
          },
          get() {
            return this.$store.getters["shopcart/isCkAll"];
          },
        },
      },
      methods: {
        // 映射actions对应的方法
        ...mapActions("shopcart", ["ckAll", "delGoodsById"]),
      },
      // 页面挂载完成
      mounted() {
        this.$store.dispatch("shopcart/loadGoodses", "data/shopcart.json");
      },
    };
    </script>
    
    购物车效果图

    相关文章

      网友评论

        本文标题:Vuex简单使用

        本文链接:https://www.haomeiwen.com/subject/yodwfrtx.html