🌈个人主页:前端青山
🔥系列专栏:Vue篇
🔖人终将被年少不可得之物困其一生
依旧青山,本期给大家带来vue篇专栏内容:vue-vuex详解
目录
Vuex
1.vuex是什么?
2.vuex核心概念
3.vuex模块化
4. Vuex中action和mutation的区别
4.1Vuex 和 localStorage 的区别
4.2Vuex有哪几种属性?
4.3Vuex和单纯的全局对象有什么区别?
4.4为什么 Vuex 的 mutation 中不能做异步操作?
4.5 Vuex的严格模式是什么,有什么作用,如何开启?
4.6如何在组件中批量使用Vuex的getter属性
4.7 如何在组件中重复使用Vuex的mutation
5.实战应用代码
Vuex
1.vuex是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
其具有以下优势:
-
能够在vuex中集中管理共享的数据,便于开发和后期进行维护
-
能够高效的实现组件之间的数据共享,提高开发效率(代码量)
-
存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新
什么样的数据适合存储在Vuex中?
一般情况下,只有组件之间共享的数据才有必要存储到vuex中,对于组件中私有的数据依旧存储在组件自身的data中即可。
注意事项:由于vue项目一刷新就会重新编译,因此每次刷新都会重新初始化vuex中的数据,会导致之前的数据丢失,因此vuex中一般不保存非常重要的数据。【放在vuex中的数据一般是刷新后也不影响业务的数据】
2.vuex核心概念
vuex的核心组成:
-
state:状态,用于初始化仓库中的数据,在这里声明项目中全局使用的数据
-
mutations:修改state数据的方法,存放用于修改state数据的方法
-
只存放同于同步修改数据的方法
-
每个方法接收俩个形参,依次是:
-
state:object,指的是仓库中的数据
-
payload:any类型,用于修改数据的数据源(可选)
-
-
函数不需要return,所有操作都是基于state直接更改
-
-
actions:修改state数据的方法,存放用于修改state数据的方法
-
只存放同于异步修改数据的方法
-
每个方法接收俩个形参,依次是:
-
context:object,指的是仓库对象(上下文对象)
-
payload:any类型,用于修改数据的数据源(可选)
-
-
函数不需要return,所有操作都是基于state直接更改
-
这里的方法本身自己不直接该数据,而是通过context对象调用mutations中的方法去修改数据
-
-
getters:获取并修饰数据(对数据进行格式处理),存储用于修饰数据的方法
-
里面的方法有一个形参
-
state:object,指的是仓库中的数据
-
-
每个函数必须有返回值,返回修饰完的数据
-
-
modules:模块化,存放模块化后的仓库模块,这里存放导入进来的模块变量
vuex语法,vuex支持对象属性形式、辅助函数形式去操作store中数据,所以每个操作都具备俩个语法:
-
获取state数据
-
对象属性:this.$store.state.属性名
-
辅助函数:mapState
-
作用:将指定的state中的数据映射为组件自身的计算属性
-
语法:
-
写在computed中
-
...mapState([属性名1,属性名2,....])
-
-
-
-
同步修改数据
-
对象属性:this.$store.commit(方法名,载荷数据)
-
辅助函数:mapMutations
-
作用:将指定的mutations中的方法映射为组件自身的方法
-
语法:
-
写在methods中
-
...mapMutations([方法名1,方法名2,...])
-
-
-
-
异步修改数据
-
对象属性:this.$store.dispatch(方法名,载荷数据)
-
辅助函数:mapActions
-
作用:将指定的Actions中的方法映射为组件自身的方法
-
语法:
-
写在methods中
-
...mapActions([方法名1,方法名2,...])
-
-
-
-
获取修饰数据
-
对象属性:this.$store.getters.属性名
-
辅助函数:mapGetters
-
作用:将指定的getters中的数据映射为组件自身的计算属性
-
语法:
-
写在computed中
-
...mapGetters([属性名1,属性名2,....])
-
-
-
3.vuex模块化
-
为什么需要模块化?
-
团队协作开发需要
-
方便后期维护管理
-
-
怎么模块化?
-
将除modules对象中的内容按照指定的拆分标准进行按文件分离
-
在index.js中导入并在modules对象中注册
-
-
有什么需要注意的?
-
因为模块化,后续的语法需要有所调整,具体见下
-
命名冲突时会执行自动合并策略
-
state,名字相同也不会冲突
-
mutations、actioms里同名方法会被合并成数组,都执行(index.js中的是最先执行的)
-
getters如果同名,无法合并,直接报错
-
-
通过命名空间来避免冲突(给每个模块开启命名空间)
-
设置模块的namespaced属性为true即可
-
-
vuex模块化后的语法:
-
获取state数据
-
对象属性:this.$store.state.模块名.属性名
-
辅助函数:mapState
-
作用:将指定的state中的数据映射为组件自身的计算属性
-
语法:
-
写在computed中
-
...mapState(模块名,[属性名1,属性名2,....])
-
-
-
-
同步修改数据
-
对象属性:this.$store.commit(模块名/方法名,载荷数据)
-
辅助函数:mapMutations
-
作用:将指定的mutations中的方法映射为组件自身的方法
-
语法:
-
写在methods中
-
...mapMutations(模块名,[方法名1,方法名2,...])
-
-
-
-
异步修改数据
-
对象属性:this.$store.dispatch(模块名/方法名,载荷数据)
-
辅助函数:mapActions
-
作用:将指定的Actions中的方法映射为组件自身的方法
-
语法:
-
写在methods中
-
...mapActions(模块名,[方法名1,方法名2,...])
-
-
-
-
获取修饰数据
-
对象属性:this.$store.getters["模块名/属性名"]
-
辅助函数:mapGetters
-
作用:将指定的getters中的数据映射为组件自身的计算属性
-
语法:
-
写在computed中
-
...mapGetters(模块名,[属性名1,属性名2,....])
-
-
-
4. Vuex中action和mutation的区别
mutation中的操作是一系列的同步函数,用于修改state中的变量的的状态。当使用vuex时需要通过commit来提交需要操作的内容。mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
state.count++ // 变更状态
}
}
})
当触发一个类型为 increment 的 mutation 时,需要调用此函数:
store.commit('increment')
而Action类似于mutation,不同点在于:
-
Action 可以包含任意异步操作。
-
Action 提交的是 mutation,而不是直接变更状态。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用
context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。 所以,两者的不同点如下:
-
Mutation专注于修改State,理论上是修改State的唯一途径;Action业务代码、异步请求。
-
Mutation:必须同步执行;Action:可以异步,但不能直接操作State。
-
在视图更新时,先触发actions,actions再触发mutation
-
mutation的参数是state,它包含store中的数据;store的参数是context,它是 state 的父级,包含 state、getters
4.1Vuex 和 localStorage 的区别
(1)最重要的区别
-
vuex存储在内存中
-
localstorage 则以文件的方式存储在本地,只能存储字符串类型的数据,存储对象需要 JSON的stringify和parse方法进行处理。 读取内存比读取硬盘速度要快
(2)应用场景
-
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex用于组件之间的传值。
-
localstorage是本地存储,是将数据存储到浏览器的方法,一般是在跨页面传递数据时使用 。
-
Vuex能做到数据的响应式,localstorage不能
(3)永久性
刷新页面时vuex存储的值会丢失,localstorage不会。
注意: 对于不变的数据确实可以用localstorage可以代替vuex,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage无法做到,原因就是区别1。
4.2Vuex有哪几种属性?
有五种,分别是 State、 Getter、Mutation 、Action、 Module
-
state => 基本数据(数据源存放地)
-
getters => 从基本数据派生出来的数据
-
mutations => 提交更改数据的方法,同步
-
actions => 像一个装饰器,包裹mutations,使之可以异步。
-
modules => 模块化Vuex
4.3Vuex和单纯的全局对象有什么区别?
-
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
-
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样可以方便地跟踪每一个状态的变化,从而能够实现一些工具帮助更好地了解我们的应用。
4.4为什么 Vuex 的 mutation 中不能做异步操作?
-
Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样可以方便地跟踪每一个状态的变化,从而能够实现一些工具帮助更好地了解我们的应用。
-
每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。
4.5 Vuex的严格模式是什么,有什么作用,如何开启?
在严格模式下,无论何时发生了状态变更且不是由mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
在Vuex.Store 构造器选项中开启,如下
const store = new Vuex.Store({
strict:true,
})
4.6如何在组件中批量使用Vuex的getter属性
使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed 对象中
import {mapGetters} from 'vuex'
export default{
computed:{
...mapGetters(['total','discountTotal'])
}
}
4.7 如何在组件中重复使用Vuex的mutation
使用mapMutations辅助函数,在组件中这么使用
import { mapMutations } from 'vuex'
methods:{
...mapMutations({
setNumber:'SET_NUMBER',
})
}
然后调用this.setNumber(10)
相当调用this.$store.commit('SET_NUMBER',10)
5.实战应用代码
import { createStore } from 'vuex'
import router from '@/router'
import qs from 'qs'
export default createStore({
state: {
// token: '',
// menuList:[],
hasRoutes: false,
editableTabsValue:'/index',
editableTabs:[
{
title: '首页',
name: '/index'
}
]
},
getters: {
GET_TOKEN: state => {
return sessionStorage.getItem("token")
},
GET_MENULIST:state => {
return JSON.parse(sessionStorage.getItem("menuList"))
},
GET_PERMS:state=>{
return JSON.parse(sessionStorage.getItem("perms"))
},
GET_USERINFO:state=>{
// console.log("GET_USERINFO="+sessionStorage.getItem("userInfo"))
return JSON.parse(sessionStorage.getItem("userInfo"))
}
},
mutations: {
SET_TOKEN: (state, token) => {
// state.token = token
sessionStorage.setItem("token", token)
},
RESET_TOKEN:(state)=>{
//state.token=''
sessionStorage.setItem("token", "")
},
SET_MENULIST:(state,menuList)=>{
//state.menuList=menuList;
sessionStorage.setItem("menuList", JSON.stringify(menuList))
},
SET_PERMS:(state,perms)=>{
sessionStorage.setItem("perms", JSON.stringify(perms))
},
SET_USERINFO:(state,userInfo)=>{
sessionStorage.setItem("userInfo", JSON.stringify(userInfo))
},
//动态添加tab
ADD_TABS:(state,tab)=>{
// debugger
// console.log("进入条件"+state.editableTabs.findIndex(e=>e.name));
if(state.editableTabs.findIndex(e=>e.name===tab.path)===-1){
// if(tab.name===undefined){
// tab.name="操作日志"
// }
state.editableTabs.push({
title: tab.name,
name:tab.path
});
}
state.editableTabsValue=tab.path
// console.log("路由列表:"+JSON.stringify(state.editableTabs))
// console.log("路由值:"+JSON.stringify(state.editableTabsValue))
},
RESET_TABS:(state)=>{
state.editableTabsValue='/index';
state.editableTabs=[
{
title: '首页',
name: '/index'
}
]
},
SET_ROUTES_STATE:(state,hasRoutes)=>{
state.hasRoutes=hasRoutes
}
},
actions: {
// 安全退出
logout(){
window.sessionStorage.clear();
this.state.hasRoutes=false
router.replace('/login')
}
},
modules: {
}
})