Vuex详解以及和事件总线的区别

Vuex是什么?

  • 官方回答:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
  • 个人理解: 支持响应式的组件之间数据共享,通俗理解将数据作为全局变量,统一放在某个地方进行统一管理。
  • 优点:
    • 能够在vuex中集中管理共享的数据,便于开发和后期进行维护
    • 能够高效的实现组件之间的数据共享,提高开发效率
    • 存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新
  • 缺点:数据的读取和修改vuex的数据需要经过,Actions或者Mutations来修改vuex的值,如果项目比较简单使用vuex就显得有些繁琐。
  • 如下图所示:
    vuex
    ok 继续,其实通过vuex的使用就能窥探一二,

先写一下vuex的大概用法:

  • 安装Vuex
  • 创建Store对象管理数据
  • 挂载Store对象到vue实例

实际操作

  • 安装Vuex
npm i -S vuex
  • 创建Store对象管理数据

①创建src/store目录,并在其中创建vuex.js文件用于导入并创建store对象

②编写src/store/vuex.js文件,基本代码如下:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    // state中存放的就是全局共享的数据
    state: {count: 0}
})
  • 挂载Store对象到vue实例
import store from '@/store/vuex'

new Vue({
    router,
    store,
    render: (h) => h(App),
}).$mount("#app");

上面的不重要:管中窥豹,如果要使用vuex,必须要挂载到Vue的实例上,并且在使用的时候用法为this.$store,挂载之后我们可以打印this来看看多了什么呢?
在这里插入图片描述

可以看到我们常用的$store,打开看看
在这里插入图片描述
是不是非常熟悉,常用的属性和方法都在,state、mutations、actions、getters等,只有一个属性state我们用来存储数据,其他的方法均用来进行操作数据使用。
那么根据官方文档提供的图:
在这里插入图片描述

  • Devtools是vuex的调试工具,方便使用者进行调试。所以设置了Mutations来进行统一管理操作,这样所有的操作都会通过Mutations而不会有第二条路径,所以在Devtools监听的时候只需要盯着Mutations即可,但是如果出现了异步操作,那么就会出现问题了呀,所以出现了actions,当有异步操作时,通过Actions之后,异步完成在执行Mutationss的同步操作,最终改变state内的数据,从而达到改变视图的目的。
  • 至于遗漏的getter以及模块化的工作,getter是对store中已有的数据加工处理形成新的数据对已有的数据进行加工除了,类似于Vue的计算属性,store数据发生变化,则getter中的数据也会跟着变化。
  • 模块化这里不多阐述,在最后进行总结模块化。

继续深化:先来看看怎么使用Mutations和Actions

  • 在Vuex中只能通过mutation变更store中的数据,不可以直接操作store中的数据
  • 通过这种方式操作起来稍微繁琐一些,但是可以集中监控所有数据的变化
// 定义mutations
const sotre = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        add(state[,arg]){
            // 变更状态
            state.count++
        }
    }
})
// 组件中触发mutation的第一种方式
methods:{
    handle(){
        this.$store.commit('add'[,arg])
    }
}
// 组件中触发mutation的第二种方式
import {mapMutations} from 'vuex'
methods:{
    ...mapMutations(['add','reduce']),
    handle1(){
        this.add()
    },
    handle2(){
        this.reduce([arg])
    }
}

使用 Actions

// 声明action
const store = new Vuex.Store({
    // 省略其他代码
    mutations: {
        add(state){
            state.count++
        }
    },
    actions: {
        addAsync(context[,arg]){
            setTimeout(() => {
                context.commit('add'[,arg])
            },1000)
        }
    }
})
// 组件中触发action
methods: {
    handle(){
        this.$store.dispach('addAsync'[,arg])
    }
}

getters类似

// 定义getter
....
getters: {
    showNum: state => {
        return '当前最新的数量是【' + state.count + '】'
    }
}
// 在组件中访问getters数据的第一种方式
this.$store.getters.全局数据名称

// 在组件中访问getters数据的第二种方式
// 按需导入mapGetters函数
import {mapGetters} from 'vuex'
// 将全局函数映射为当前组件的计算属性
computed: {
    ...mapGetters(['showNum'])
}
  • 怎么使用不是重点,重点是我们要知道,为什么要使用computed而不是data或者methods获取vuex中的state、getters呢?因为data 中的内容只会在 created 钩子触发前初始化一次,赋值之后属性的值就是纯粹的字面量,之后this.$store.state.xxx 如何变化均影响不到count的取值。

对比bus总线

看了这么多东西,你是不是也觉得和bus总线非常的相似,但是他们有本质的区别,并且通过vuex响应式的特点可以清楚的知道,他和数据双向绑定的原理一样,使用了getter和setter进行数据劫持。

  • 本质上最大的区别:bus利用事件抛发的原理进行传递数据而vuex通过数据劫持,并且复制一份相同的_data来进行数据管理.
  • 举个栗子:bus相当于打电话,中间商只是接到电话消息传递给第三方,而vuex是你写的消息,它保留一份下来,必须要通过它来管理你的消息,不管是你要怎么处理消息。还有一个好处,vuex分离了数据和视图,让代码更加的清晰和方便维护。
  • 个人理解:其实在跨组件传输中,本质上都是一个方法,因为我们所有的组件也好,操作也好都是在vue这个实例上去实现的,所以Vue就是所有组件都可以访问到的一个对象,那么我们将数据保存在Vue的prototype上时,无论我们在哪一个组件,都可以访问到数据了。

模块化思想

  • 为什么有状态的模块化?主要是因为项目是多人协作开发的,如果都去修改一个文件,则经常会出现代码冲突,而解决冲突比较费事费力。
  • 使用步骤
    • 建立src/store/modules文件夹(名称随意)
    • 在modules文件夹中建立需要的模块文件(命名以功能为导向,记得导出一下)
  • 注意点1(了解):
    • 在模块的时候,因为多人合作,不能的开发者之前并不清楚其他怎么给方法和数据源进行命名,这样的话就有一个问题:万一名称重名怎么办?如果冲突了,会执行以下合并策略:
      • state数据源肯定不会冲突,它以模块进行保存
      • mutations、actions的方法不会以模块为单位进行保存,如果出现同名则可能会冲突。vuex会先将这些同名的方法,整合到一起,都去执行。会先执行index.js中的,再去执行其他的。
      • getters如果出现冲突,不给解决,直接报错。
    • 因为多人合作可能出现命名的冲突,特别针对getters,vuex模块化的时候支持使用命名空间
      • 默认是没有给模块开启命名空间的
      • 如果需要请自己开启,通过模块对象的属性“namespaced”,将其值设置为true
      • 命名空间的名称,是模块的名字(模块里面属性的名字)
  • 注意点2:由于模块使用了命名空间,所以之前没有模块化的使用方式(this、map系列)在模块化之后都要发生对应的变化
    • state
      • this形式:this.$store.state.空间名.xxxx
      • map系列:…mapSate(空间名,[xxxx,yyyy,zzzz…])
    • mutations
      • this形式:this.$store.commit(“空间名/方法名”, “参数”);
      • map系列:…mapMutations(“空间名”,[“方法名”,…]),
    • actions
      • this形式:this.$store.dispatch(“空间名/方法名”, “参数”);
      • map系列:…mapActions(“空间名”,[“方法名”,…]),
    • getters
      • this形式:this.$store.getters[“空间名/属性名”]
      • map形式:…mapActions(“空间名”, [“属性名”,…]),
  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MaxLoongLvs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值