vue-------vuex状态管理器
状态管理器
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
并不需要把所有的组件的状态都放在状态管理器,但是它确实都可以放在状态管理器
- 什么时候使用状态管理器?
来不同的视图需要依赖同一个状态
来自不同视图的行为需要变更同一个状态
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)
- Vuex 和单纯的全局对象有以下两点不同:
- Vuex 的状态存储是响应式的。
当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。 - 你不能直接改变 store 中的状态。
改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用
状态管理器基本写法
import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: { // 状态管理器管理的状态,罗列出来即可
a: 1,
b: 2,
c: 3
},
mutations: { // 唯一改变状态的地方
changeA (state) {
state.a = '11'
},
changeB (state) {
state.b = '22'
},
changeC (state, data) {
state.c = data
}
}
})
export default store
- 如何改变状态
import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: { // 状态管理器管理的状态,罗列出来即可
a: 1,
b: 2,
c: 3
},
mutations: { // 唯一改变状态的地方
changeA (state) {
state.a = '11'
},
changeB (state) {
state.b = '22'
},
changeC (state, data) {
state.c = data
},
changeD (state, data) { // 传入对象 触发2种写法
state.c = data.payload
}
}
})
console.log(store)
// 如果需要在组件中修改状态管理器状态,引入状态管理器,执行如下代码// store.commit('changeA')console.log(store.commit('changeA')) // undefined
store.commit('changeB')
store.commit('changeC', '333333333333333')
store.commit('changeD', { // 触发传入对象第一种写法
payload: '4444444444'
})
store.commit({ // 触发传入对象第2种写法
type: 'changeD',
payload: '555555'
})
console.log(store.state)
export default store
- 模拟真实场景 --- 异步操作在组件
import Vue from 'vue'import Vuex from 'vuex'import { getProlist } from '@/api'
Vue.use(Vuex)
const store = new Vuex.Store({
state: { // 状态管理器管理的状态,罗列出来即可
prolist: []
},
mutations: { // 唯一改变状态的地方
changeProlist (state, data) {
state.prolist = data.payload
}
}
})
console.log(store.state)
// 以下操作在组件中// 引入状态管理器
getProlist().then(res => {
store.commit({
type: 'changeProlist',
payload: res.data.data
})
console.log(store.state)
})
export default store
- 模拟真实场景 - 异步操作在状态管理器
import Vue from 'vue'import Vuex from 'vuex'import { getProlist } from '@/api'
Vue.use(Vuex)
const store = new Vuex.Store({
state: { // 状态管理器管理的状态,罗列出来即可
prolist: []
},
actions: { // 将组件的异步操作在此操作
getProlistAction (context) { // context其实就类似于 this,其实就是当前的store
// 如果获取到数据有后续操作,可以使用promise封装actions
// getProlist().then(res => {
// context.commit({
// type: 'changeProlist',
// payload: res.data.data
// })
// })
// 比如你要上拉加载,下拉刷新,结束之后可以继续在组件中操作
return new Promise((resolve, reject) => {
getProlist().then(res => {
context.commit({
type: 'changeProlist',
payload: res.data.data
})
resolve()
})
})
}
},
mutations: { // 唯一改变状态的地方
changeProlist (state, data) {
state.prolist = data.payload
}
}
})
console.log(store.state)
// 组件中只需要 dispatch action即可 --- 简化了组件的代码,缩小组件的体积// store.dispatch('getProlistAction')// 上拉加载中页码 count ,有没有数据状态 finished 一般放在组件
store.dispatch('getProlistAction').then(() => {
// 比如执行上拉加载中页码加1,拼接数据
})
export default store
- 状态管理器的计算属性
import Vue from 'vue'import Vuex from 'vuex'import { getProlist } from '@/api'
Vue.use(Vuex)
const store = new Vuex.Store({
state: { // 状态管理器管理的状态,罗列出来即可
prolist: []
},
getters: { // 计算属性
getProlistLen (state) {
return state.prolist.length
}
},
actions: { // 将组件的异步操作在此操作
getProlistAction (context) { // context其实就类似于 this,其实就是当前的store
// 如果获取到数据有后续操作,可以使用promise封装actions
// getProlist().then(res => {
// context.commit({
// type: 'changeProlist',
// payload: res.data.data
// })
// })
// 比如你要上拉加载,下拉刷新,结束之后可以继续在组件中操作
return new Promise((resolve, reject) => {
getProlist().then(res => {
context.commit({
type: 'changeProlist',
payload: res.data.data
})
resolve()
})
})
}
},
mutations: { // 唯一改变状态的地方
changeProlist (state, data) {
state.prolist = data.payload
}
}
})
console.log(store.state)
// 组件中只需要 dispatch action即可 --- 简化了组件的代码,缩小组件的体积// store.dispatch('getProlistAction')// 上拉加载中页码 count ,有没有数据状态 finished 一般放在组件
store.dispatch('getProlistAction').then(() => {
// 比如执行上拉加载中页码加1,拼接数据
// 获取计算属性的值
console.log(store.getters)
})
export default store
- 为了状态管理器的方便管理,会划分模块 -- 按照功能
import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)
const moduleA = {
state: {
a: 1
},
mutations: {
changeA (state) {
state.a = '111'
}
}
}
const moduleB = {
state: {
b: 2
},
mutations: {
changeB (state) {
state.b = '222'
}
}
}
const moduleC = {
state: {
c: 3
},
mutations: {
changeC (state) {
state.c = '333'
}
}
}
// 加入有非常多个状态,我们放在一起管理,维护代价太高// 模块化 --- 功能 、 页面 、组件// 功能 - 登陆、注册、用户的各种状态 / 购物车相关 / 分类 / 搜索// 每一个功能模块 都至少有 state 和 mutations,可以含有 actions和getters// 创建状态管理器时整合 功能模块const store = new Vuex.Store({
modules: {
moduleA,
moduleB,
moduleC
}
})
console.log(store)
console.log(store.state) // 拿到所有的状态 ---- 对象模式console.log(store.state.moduleA.a) // 获取moduleA模块中的状态// 改变状态 ---- 唯一改变状态的方式就是显示的提交mutation// 提交的 mutation 不分模块,相当于把所有的mutations放到了一起
store.commit('changeA')
console.log(store.state.moduleA.a)
export default store
- 如果两个模块中的 mutations 重名怎么办?
模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)
// 模块中的mutations其实最后是不分的,多个模块可能存在重名的情况 ---- 每个模块添加一个命名空间const moduleA = {
namespaced: true,
state: {
a: 1
},
mutations: {
changeA (state) {
state.a = '111'
}
}
}
const moduleB = {
namespaced: true,
state: {
b: 2
},
mutations: {
changeB (state) {
state.b = '222'
}
}
}
const moduleC = {
namespaced: true,
state: {
c: 3
},
mutations: {
changeC (state) {
state.c = '333'
}
}
}
// 加入有非常多个状态,我们放在一起管理,维护代价太高// 模块化 --- 功能 、 页面 、组件// 功能 - 登陆、注册、用户的各种状态 / 购物车相关 / 分类 / 搜索// 每一个功能模块 都至少有 state 和 mutations,可以含有 actions和getters// 创建状态管理器时整合 功能模块const store = new Vuex.Store({
modules: {
moduleA,
moduleB,
moduleC
}
})
console.log(store)
console.log(store.state) // 拿到所有的状态 ---- 对象模式console.log(store.state.moduleA.a) // 获取moduleA模块中的状态// 改变状态 ---- 唯一改变状态的方式就是显示的提交mutation// 提交的 mutation 不分模块,相当于把所有的mutations放到了一起
store.commit('moduleA/changeA')
console.log(store.state.moduleA.a)
export default store
- 模拟组件
import Vue from 'vue'import Vuex from 'vuex'import { getProlist, getCategoryBrandList } from '@/api'
Vue.use(Vuex)
// 模块中的mutations其实最后是不分的,多个模块可能存在重名的情况 ---- 每个模块添加一个命名空间const home = {
namespaced: true,
state: {
list: []
},
actions: {
getListAction ({ commit }) {
return new Promise(resolve => {
getProlist().then(res => {
commit({
type: 'changeList',
payload: res.data.data
})
resolve()
})
})
}
},
mutations: {
changeList (state, data) {
state.list = data.payload
}
}
}
const kind = {
namespaced: true,
state: {
list: []
},
actions: {
getListAction ({ commit }) {
return new Promise(resolve => {
getCategoryBrandList({
type: '手机',
brand: 'huawei'
}).then(res => {
commit({
type: 'changeList',
payload: res.data.data
})
resolve()
})
})
}
},
mutations: {
changeList (state, data) {
state.list = data.payload
}
}
}
const store = new Vuex.Store({
modules: {
home,
kind
}
})
// 模拟组件操作
store.dispatch('home/getListAction').then(() => {
console.log('home', store.state.home)
})
store.dispatch('kind/getListAction').then(() => {
console.log('kind', store.state.kind)
})
export default store
- 如果异步操作用于actions中,但是触发acitons时,如果需要传递参数呢?
import Vue from 'vue'import Vuex from 'vuex'import { getProlist, getCategoryBrandList } from '@/api'
Vue.use(Vuex)
// 模块中的mutations其实最后是不分的,多个模块可能存在重名的情况 ---- 每个模块添加一个命名空间const home = {
namespaced: true,
state: {
list: []
},
actions: {
getListAction ({ commit }, params) {
console.log('params', params)
return new Promise(resolve => {
getProlist(params).then(res => {
commit({
type: 'changeList',
payload: res.data.data
})
resolve()
})
})
}
},
mutations: {
changeList (state, data) {
state.list = data.payload
}
}
}
const kind = {
namespaced: true,
state: {
list: []
},
actions: {
getListAction ({ commit }) {
return new Promise(resolve => {
getCategoryBrandList({
type: '手机',
brand: 'huawei'
}).then(res => {
commit({
type: 'changeList',
payload: res.data.data
})
resolve()
})
})
}
},
mutations: {
changeList (state, data) {
state.list = data.payload
}
}
}
const store = new Vuex.Store({
modules: {
home,
kind
}
})
// 模拟组件操作
store.dispatch('home/getListAction', { count: 1, limit: 15 }).then(() => {
console.log('home', store.state.home)
})
store.dispatch('kind/getListAction').then(() => {
console.log('kind', store.state.kind)
})
export default store
- 使用常量替代 Mutation 事件类型 - AC
import Vue from 'vue'import Vuex from 'vuex'import { getProlist, getCategoryBrandList } from '@/api'import { CHANGE_LIST } from './mutation-types'
Vue.use(Vuex)
// 使用常量代替mutations// 使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名const home = {
namespaced: true,
state: {
list: []
},
actions: {
getListAction ({ commit }, params) {
console.log('params', params)
return new Promise(resolve => {
getProlist(params).then(res => {
commit({
type: CHANGE_LIST,
payload: res.data.data
})
resolve()
})
})
}
},
mutations: {
[CHANGE_LIST] (state, data) {
state.list = data.payload
}
}
}
const kind = {
namespaced: true,
state: {
list: []
},
actions: {
getListAction ({ commit }) {
return new Promise(resolve => {
getCategoryBrandList({
type: '手机',
brand: 'huawei'
}).then(res => {
commit({
type: CHANGE_LIST,
payload: res.data.data
})
resolve()
})
})
}
},
mutations: {
[CHANGE_LIST] (state, data) {
state.list = data.payload
}
}
}
const store = new Vuex.Store({
modules: {
home,
kind
}
})
// 模拟组件操作
store.dispatch('home/getListAction', { count: 1, limit: 20 }).then(() => {
console.log('home', store.state.home)
})
store.dispatch('kind/getListAction').then(() => {
console.log('kind', store.state.kind)
})
export default store
项目中使用状态管理器
登陆状态相关
底部组件中判定登陆状态
首页头部需要判定
登陆页面修改登陆的业务逻辑
上图有坑
个人中心显示登陆还是注册
-----------------------------------------------------文章来自吴大勋(大勋说)链接