![12e54b462d16435e5003773cd8d575d6.png](https://img-blog.csdnimg.cn/img_convert/12e54b462d16435e5003773cd8d575d6.png)
vuex简介
- Vuex是一个为Vue.js应用程序开发的状态管理模式
-
- 采用集中式存储管理应用的所有组件的状态,并且相应的规则保证状态以一种可预测的方式发生变化
- Vuex也集成到Vue的官方调试工具 devtools extension,提供了注入令配置的time-travel调试,状态快照导入导出功能
- 状态管理是什么:
-
- 可以简单的将其看成把需要的多个组件共享的变量全部存储在一个对象里面
- 然后将这个对象放在顶层的Vue实例中,让其他组件可以使用
- 那么,多个组件就可以共享这个对象中的所有变量属性了
- 简单来说就是多个组件需要共享一个状态(或者是变量),那么这个状态放在哪个组件中都不合适,那么就单独的new一个对象,把这个对象看作是一个管家,来管理这些共享的状态信息
- 有什么状态时需要多个组件共享:
- 如果一个项目,存在多个界面共享问题
- 比如用户的登陆状态,用户名称,头像,地理位置信息,商品收藏,购物车中的物品等等
- 这些状态信息,都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的
Vuex 安装
- 命令行安装
npm install vuex --save
- 在src文件夹下创建 store文件夹,在该文件夹下创建 index.js文件,其中写入:
import Vue from "vue";import Vuex from "vuex"//1. 安装插件Vue.use(Vuex);//2. 创建vuex对象const store = new Vuex.Store({ state: {}, mutations: {}, actions: {}, getters: {}, modules: {}})//3. 导出story对象export default store;
- 在main.js文件中引入vuex对象
import Vue from 'vue'import App from './App'import router from './router'//引入 vuex 的store对象import store from "./store";Vue.config.productionTip = falsenew Vue({ el: '#app', router, store, render: h => h(App)})
通过 mutation 修改vuex管理的状态
- 要修改vuex管理的状态必须通过mutation
- index.js文件
import Vue from "vue";import Vuex from "vuex"//1. 安装插件Vue.use(Vuex);//2. 创建vuex对象const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 counter: 10 }, mutations: {//定义方法用于修改vuex管理的状态 increment(state){ state.counter++; }, decrement(state){ state.counter--; } }, actions: {}, getters: {}, modules: {}})//3. 导出story对象export default store;
- App.vue文件
{{$store.state.counter}}
+ -
- 具体描述
- 提取出一个公共的store对象,用于保存多个组件中共享的状态
- 将store对象放置在 new Vue对象中,这样可以保证在所有的组件中都可以使用到
- 在其他组件中使用store对象中保存的状态即可
- 通过 this.$store.属性 的方式来访问状态
- 通过 this.$store.commit('mutation方法名') 来修改状态
- 注意事项:
- 通过提交 mutation的方式,而非直接改变 store.state.属性
- 这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.counter 的值
vuex Getters 的使用
- 有时候,需要从store 中获取一些state 变异后的状态
- 在组件中需要拿到 store中的数据,而且这个数据是需要变化后才给到组件或者页面的时候,这时就需要永高getters
- 抽取出的vuex的index.js配置文件
import Vue from "vue";import Vuex from "vuex"//1. 安装插件Vue.use(Vuex);//2. 创建vuex对象const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 students: [ {id: 1, name: 'bob', age: 18}, {id: 2, name: 'kobe', age: 22}, {id: 3, name: 'xyx', age: 25}, {id: 4, name: 'john', age: 17} ] }, getters: { //这里定义的是state中变化后的内容 more20stu(state){ return state.students.filter(s => s.age > 20); } }})//3. 导出story对象export default store;
getters中定义的powerConter内容----
{{$store.getters.powerConter}}
通过getters 中的more20stu 获取state中age大于20的对象---
{{$store.getters.more20stu}}
getters作为参数和传递参数
- 作为参数
- 以上面的代码为例,如果需要拿到 {{$store.getters.more20stu}} 获取的学生的个数
- 在getters中定义的函数还可以传入第二个参数
import Vue from "vue";import Vuex from "vuex"//1. 安装插件Vue.use(Vuex);//2. 创建vuex对象const store = new Vuex.Store({ state: { counter: 10, students: [ {id: 1, name: 'bob', age: 18}, {id: 2, name: 'kobe', age: 22}, {id: 3, name: 'xyx', age: 25}, {id: 4, name: 'john', age: 17} ] }, getters: { more20stu(state){ return state.students.filter(s => s.age > 20); }, //传入的第二个参数代表就是当前对象中的getters more20stuLenthg(state,getters){ return getters.more20stu.length; } },})//3. 导出story对象export default store;
通过getters 中的more20stu 获取state中age大于20的对象---
{{$store.getters.more20stu}}
getters 作为参数
{{$store.getters.more20stuLenthg}}
- 传递参数
- getters默认是不能传递参数的,如果希望传递参数,那么只能让getters本身返回另一个函数
- 要获取年龄大于 age的stu对象,age由外部传递进来
import Vue from "vue";import Vuex from "vuex"Vue.use(Vuex);const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 counter: 10, students: [ {id: 1, name: 'bob', age: 18}, {id: 2, name: 'kobe', age: 22}, {id: 3, name: 'xyx', age: 25}, {id: 4, name: 'john', age: 17} ] }, getters: { //获取年龄大于 age 的学生,这个Age不是写死的,而且别的地方传入进来的 moreAgeStu(state) { //返回一个函数 return function (age) { return state.students.filter(s => s.age > age); } } }})//3. 导出story对象export default store;
getters 传递参数----
{{$store.getters.moreAgeStu(22)}}
mutainons 携带参数
- vuex的store状态的更新唯一方式是:提交Mutations
- mutations主要包括两部分
- 字符串的事件类型(type)
- 一个回调函数(handler) ,该回调函数的第一个参数就是state
- mutations的定义方式:
mutations: { increment(state){ state.count++; }}
- 通过mutations更新
increment: function(){ this.$stote.commit('increment')}
- 之前的mutations改变counter是每次 ++ 或者 --,现在需要每次点击按钮 + 多少 -多少由外部传入
mutations: { // 第二个参数是外部传入的 incrementCount(state,count){ state.counter += count; }},
mutations 传递参数----
{{this.$store.state.counter}}
+5 +10
- mutitaions传递参数就是在提交comiit的时,commit的第二个参数就是传递给mutations的参数
mutitaions 传入多个参数
- 多个参数使用一个对象传入
addStu(){ const stu = {id: 5, name: 'alan', age:30}; this.$store.commit('addSutdent',stu);}
mutations提交风格
- 之前通过commit进行提交是一种普通的方式
- Vue还提供了另外一种风格,它是一个包含type属性的对象,被称为mutations负载(payload)
addCount(count){ //普通的提交风格 //this.$store.commit('incrementCount',count); //特殊的提交风格 this.$store.commit({ type: 'incrementCount', count })},
mutations: {//定义方法用于修改vuex管理的状态 incrementCount(state,payload){ state.counter += payload.count; }}
mutations响应规则
- vuex的store中的state是响应式的,当state中的数据发生改变时,vue组件会自动更新
- 这就要求必须遵守一些vuex对应的规则
- 提前在store中初始化好所需的属性
- 当给state中的对象添加新属性时,使用下面的方式
- 方式一: 使用 Vue.set(obj, 'newProp', 123)
- 方式二: 用新对象给旧对象重新赋值
- 给state中定义好的对象添加属性
store.state.info的内容是否是响应式的-------
修改 info
{{$store.state.info}}
import Vue from "vue";import Vuex from "vuex"Vue.use(Vuex);const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 info: { name: 'xiaoyouxin', age: 25, height: 1.75 } }, mutations: {//定义方法用于修改vuex管理的状态 //通过Vue.set(obj, key, value) 响应式的修改info的信息 updateInfo(state){ Vue.set(state.info, 'addr', '重庆'); } } })export default store;
- 给state中定义好的对象删除属性
import Vue from "vue";import Vuex from "vuex"Vue.use(Vuex);const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 info: { name: 'xiaoyouxin', age: 25, height: 1.75 } }, mutations: {//定义方法用于修改vuex管理的状态 deleteInfo(state){ //删除属性该方式做不到响应式 // delete state.info.name; Vue.delete(state.info, 'name'); } } })export default store;
mutation常量类型
- 在mutation中,自定义了很多事件类型(也就是其中的方法名称)
- 当项目增大时,vuex管理的状态越来越多,需要更新状态的情况越来越多,那么意味着mutation中的方法越来越多
- 方法过多,使用者需要花费大量的精力去记住这些方法,甚至是多个文件之间来回切换,查看方法名称,甚至如果不是复制的时候,可能还会出现写错的情况
- 这时候可以在store文件夹下创建一个js文件用于保存常量
export const INCREMENT = 'increment';export const INCREMENTCOUNT = 'incrementCount';export const DECREMENT = 'decrement';export const ADDSTUDENT = 'addSutdent';export const UPDATEINFO = 'updateInfo';export const DELETEINFO = 'deleteInfo';
- 然后再index.js文件中引入这些常量,并修改mutations中的方法名为 :
import Vue from "vue";import Vuex from "vuex"// 引入这些常量import { INCREMENT,DELETEINFO,DECREMENT,ADDSTUDENT,UPDATEINFO,INCREMENTCOUNT} from './mutations-types'Vue.use(Vuex);const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 counter: 10, students: [ {id: 1, name: 'bob', age: 18}, {id: 2, name: 'kobe', age: 22}, {id: 3, name: 'xyx', age: 25}, {id: 4, name: 'john', age: 17} ], info: { name: 'xiaoyouxin', age: 25, height: 1.75 } }, mutations: { //修改方法名为 : [常量](){} 的方式 [INCREMENT](state) { state.counter++; }, [DECREMENT](state) { state.counter--; }, [INCREMENTCOUNT](state,payload){ state.counter += payload.count; }, [ADDSTUDENT](state,stu){ state.students.push(stu); }, [UPDATEINFO](state){ Vue.set(state.info, 'addr', '重庆'); }, [DELETEINFO](state){ Vue.delete(state.info, 'name'); } }})export default store;
- 在组件中使用这些常量
mutations 传递参数----
{{this.$store.state.counter}}
+5 +10
mutations 传递参数2----
添加学生 {{$store.state.students}}
store.state.info的内容是否是响应式的-------
修改 info 添加属性
{{$store.state.info}}
修改 info 删除属性
{{$store.state.info}}
Action 基本定义
- 通常情况下Vuex要求mutation中的方法必须是同步方法
- 主要原因是当我们使用devtools时,devtools可以帮助我们捕捉mytations的快照
- 但是如果是异步操作,那么devtools将不能很好的追踪这个操作由什么时候被完成
- 如果有些情况下,确实需要在vuex中进行一些异步操作,比如网络请求,必然时异步的,这时候使用Action,Action类似于mutations,但是是来替代mutations进行异步操作的
- 用法,在组件中需要异步修改state中的属性
- $this.store.dispatch('Action中的函数名')
- Action中定义的异步函数内部通过mutitaons修改state中的属性
import Vue from "vue";import Vuex from "vuex"import { INCREMENT,DELETEINFO,DECREMENT,ADDSTUDENT,UPDATEINFO,INCREMENTCOUNT} from './mutations-types'Vue.use(Vuex);const store = new Vuex.Store({ state: { //定义被vuex管理的各个状态 info: { name: 'xiaoyouxin', age: 25, height: 1.75 } }, mutations: { [UPDATEINFO](state){ Vue.set(state.info, 'addr', '重庆'); } }, actions: { //在actions中定义的函数中异步调用mutations中的方法 aUpdateInfo(context){ setTimeout(() => { context.commit(UPDATEINFO) },1000) } }})export default store;
修改 info 添加属性
{{$store.state.info}}
注意: action传递参数的方式根mutitaions的方式一致
modules 的使用
- vue使用单一状态树,那么也意味着很多状态都会交给vuex来管理
- 当应用变得非常复杂时,store对象就有了能变得相当臃肿
- 为了解决这个问题,vuex允许将store分割成模块,而每个模块都拥有自己的state,mutations,actions,gettets等
- 定义在模块中的东西使用方式和之前是一样的,不做过多笔记
- 不过getters中定义的函数除了 state,getters之外还可呢传入第三个参数 rootState,这个参数表示之前没有用模块分割的哪个state,可以从这个参数中取出原本定义好的属性
- 还有一个就是在modules中的cations中定义的函数commit的时候是针对于自己这个模块中的mutations的
项目结构
- 当vuex管理过多内容时,好的项目结构可以使代码更加清晰
- index.html
- main.js
- api
- ... 抽取出的API请求
- components
- App.vue
- ...
- store
- index.js 组装模块并导出store的地方
- actions.js 根级别的 action
- mutations.js 根级别的mutation
- modules
- cart.js 购物车模块
- user.js 用户模块