VUEX详解

1、定义:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

2、特点:

(1)能够在vuex中 集中管理共享的数据,易于开发和后期维护

(2)能够高效地实现组件之间的数据共享, 提高开发效率

(3)存储在 vuex中的数据都是响应式的,能够实时保持数据与页面的同步

(4)一般情况下,只有组件之间共享的数据,才有必要存储到vuex中;

(5)对于组件中的私有数据,依旧存储在组件自身的data中即可.

3、使用场景

如果你实在不知道开发中什么数据才应该保存到Vuex中,那你就先不用Vuex,需要的时候自然就会想到它;为了方便实现组件之间的数据共享,Vuex是他们团队借鉴了redux,用来实现vue组件全局状态(数据)管理的一种机制.

4、这个状态自管理应用包含以下几个部分:

state,驱动应用的数据源;存放数据,组件之间共用的状态,与组件各自之间的关系无关

view,以声明方式将 state 映射到视图;

actions,响应在 view 上的用户输入导致的状态变化。

组件(模板)view 数据发生改变-----------actions(vue+vuex)--------state(vuex)----组件(模板)view;

 5、使用步骤:

(1)要使用vuex就要先安装--------cnpm install vuex --save

(2)创建使用store使用state

在src下创建store文件夹,并在文件夹下创建index.js 填入以下代码

import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 启用vuex
Vue.use(Vuex)

// 创建vuex实例
export default new Vuex.Store({
    state: {},
    mutations: {},
    actions: {},
    modules: {}
})

(3)将这个vuex实例引入main.js并挂在到vm对象上 

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
/** 引入仓库实例 */
import store from './store'

const app = createApp(App);
app.config.unwrapInjectedRef = true
app.use(store).use(router).mount('#app')

简单使用:在store/index.js state对象中写上一个状态

state: {
       isShowHeader: false
  }

在组件中view上通过$store.state.isShowHeader获取并使用,通过点击事件更改状态

<template>
  <div id="app">
    <div v-if="$store.state.isShowHeader" class="header">
      <ul>
        <li>首页</li>
        <li>游戏</li>
        <li>下载</li>
        <li>我的</li>
        <li>联系我们</li>
      </ul>
    </div>
    <button @click="changeShowHeaderState">点击切换状态</button>
    <router-view></router-view>
  </div>
</template>
<script>

export default {
  name: "App",
  data() {
    return {
		obj: {
            ages: {
                age: 18
            }
        }
    }
  },
  watch: {
    '$store.state.isShowHeader': function() {
        
    },
     'obj.ages.age': function() {
         
     }
  }
  methods: {
    changeShowHeaderState() {
      const state = this.$store.state.isShowHeader;
      const age = this.obj.ages.age;
      this.$store.state.isShowHeader = state === true ? false : true;
    }
  }
};
</script>

在此后,无论哪一个组件更改了,在其他组件就会拿到最新的状态值。

举个复杂一点的小栗子:在src下的store文件夹里面创建一个购物功能的仓库,并在组件里面使用它的功能。

interface itemBuyNumTypeI {
  index: number;
  n: number;
}
interface itemTypeI {
  id: number;
  title: string;
  num: number;
  price: number;
  cover: string;
}

export default createStore({
  state: {
    cars: [] as Array<itemTypeI>
  },
  getters: {
    totalNum(state) {
      return state.cars.reduce((pV, currentItem) => pV + currentItem.num, 0);
    },
    totalMoney(state) {
      return state.cars.reduce((pV, currentItem) => pV + currentItem.num * currentItem.price, 0);
    }
  },
  mutations: {  /** 不能有异步处理 */
    addItem2Cars(state, item) {
      console.log(state);
      const ind = state.cars.findIndex(p => p.id === item.id);
      /** 没找着直接追加 */
      if (ind === -1) {
        state.cars.push(item);
      } else {
        /** 找到了,就修改购买数量 */
        state.cars[ind].num += item.num;
      }
    },
    itemBuyNum(state, pidN: itemBuyNumTypeI) {
      // 至少是  1
      if (state.cars[pidN.index].num === 1 && pidN.n == -1) return;

      state.cars[pidN.index].num += pidN.n;
    },
    /** 购物车初始化 */
    carsInit(state, itemArr) {
      state.cars = JSON.parse(JSON.stringify(itemArr));
    }
  },
  actions: {  /** 异步处理 */
    carsInit(context) {
      /** 如果已经有数据了,就不用初始化了 */
      if (context.state.cars.length) return;
      getCarsItems().then(res => {
        console.log(res);
        /** 修改数据还是必须且只能通过mutation */
        context.commit('carsInit', res.data);
      }).catch(err => {
        console.log(err);
      });
    }
  },
  modules: {
  }
})

在组件里面使用:

<template>
  <div>
    我是A组件,数据: <span>{{ msg }}</span>
    <ul class="cars">
      <li v-for="(p, ind) in cars" :key="p.id">
        <div class="left">
          <img :src="p.cover" :alt="p.title" />
        </div>
        <div class="right">
          <div class="top">
            {{ p.title }}
          </div>
          <div class="num">
            购买数量:
            <div>
              <button @click="itemNumInc({ index: ind, n: -1 })">--</button>
              <input type="number" v-model="p.num" />
              <button @click="itemNumInc({ index: ind, n: 1 })">++</button>
            </div>
          </div>
          <div class="price">价格:{{ p.price }}</div>
        </div>
      </li>
      <li>
        <div class="left">商品总数:{{ totalNum }}</div>
        <div class="right">商品总价:{{ totalMoney }}</div>
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
interface itemTypeI {
  id: number;
  title: string;
  num: number;
  price: number;
  cover: string;
}
interface itemBuyNumTypeI {
  index: number;
  n: number;
}
export default defineComponent({
  components: {},
  /** 我们通过计算属性使用Vuex里面的数据*/
  computed: {
    cars(): Array<itemTypeI> {
      return this.$store.state.cars;
    },
    totalNum(): number {
      return this.$store.getters.totalNum;
    },
    totalMoney(): number {
      return this.$store.getters.totalMoney;
    },
  },
  data() {
    return {
      msg: '我是组件A的数据',
    };
  },
  methods: {
    itemNumInc(pidN: itemBuyNumTypeI) {
      this.$store.commit('itemBuyNum', pidN);
    },
  },
  mounted() {
    //初始化购物车历史数据
    this.$store.dispatch('carsInit');
  },
});
</script>

(4)解剖--state、mutation 、action和getters

    i.State:{}存放数据,组件之间共用的状态,与组件关系无关.

   ii.Getters:{}--  相对于vue里面计算属性computed

        大家可能会发现我们的流程图中并没有getter,那getter到底是什么呢?

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

场景:就像上面举的栗子一样,我们需要计算得到商品购买数量和价格时就要使用到

    iii.Mutations:{}不同组件里面对数据进行修改(唯一的修改数据的方式),用了action也还要在mutation里面去初始方法)---必须是同步的,必须有载荷和参数。

    那为什么通过mutation来修改呢?因为mutation会被DevTools记录,方便查找问题(DevTools,打开github,搜索devtools,翻到项目后边可以下载对应浏览器的tool需要翻墙)

   iv.Actions:支持同步和异步,最终要修改数据还是要通过mutation来完成。

类似于 mutation,不同在于:

(1) Action 提交的是 mutation,而不是直接变更状态。
(2)Action 可以包含任意异步操作

使用方式:

          view层通过this.$store.dispatch('getListDataAction'); 触发事件为getListDataAction的action

在action中发起异步请求,获取数据,然后调用store.commit('listDataMutation', res.data);(store为action的参数,vuex自自动传入)

触发事件为listDataMutation的mutation

mutation中将提交需要更改的state状态

state状态更新成功后映射到页面上

案例:组件之间来回切换时,如果组件中的数据来自于服务器,就意味中一直切换将会一直发起数据,如果有一个东西可以缓存起来的话,在下一次切换时就不会在发起请求了

6、缺点:团队项目中,如果有谁改了这个状态出bug了,那谁知道是谁改的呢?这个全局变量很好用,但是团队项目中还是比较容易出问题,而且一旦出问题就很难排查,所以需要引入一套管理机制,去负责修改这些状态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值