一、Vuex之集成
1. 功能
处理前端路由的功能
2. 安装
npm install vuex --save
3. 集成
在项目中新建两个文件(store文件夹下)
index.js // 路由配置
routes.js // 路由内容
3.1 index.js
存放路由配置
- 3.2.1 方式一:返回一个Vuex对象,全局import时皆为统一对象,不会自动释放,所以在使用服务端渲染时会导致内存溢出
import Vue from 'vue'
import Vuex from 'vuex'
// 使用Vuex
Vue.use(Vuex)
export default new Vuex.Store({
state: {
counts: 0
},
mutations: {
updateCount (state, num) {
state.count = num
}
}
})
- 3.2.2 方式二:返回一个方法,每次import创建一个新的Vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 使用Router
Vue.use(Vuex)
// 判断是否处于开发环境
const isDev = process.env.NODE_ENV === 'development'
export default () => {
return new Vuex.Store({
// 开启后不可以在外部直接修改state,只可在开发环境中使用
strict: isDev
state: {
counts: 0
},
mutations: {
updateCount (state, num) {
state.count = num
}
}
})
}
3.2 main.js
import createStore from './store/index.js'
// 将store放入new Vue的配置项中
const store = createStore()
new Vue({
store: store
})
3.3 Component.vue (Vuex的使用)
通过this.$store
使用
// store对象
this.$store
// state
this.$store.state.count
// mutations
this.$store.commit('updateCount', i)
二、Vuex之state和getters
1. 文件夹结构
+ store
+ state
state.js
+ mutations
mutations.js
+ getters
getters.js
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import defaultState from './state/state.js'
import mutations from './mutations/mutation.js'
import getters from './getters/getters.js'
// 使用Router
Vue.use(Vuex)
export default () => {
return new Vuex.Store({
// 服务端渲染时会覆盖state,所以此时使用defaultState
state: defaultState,
// 操作与数据无关
mutations,
getters
})
}
2. state
2.1 声明
export default {
count: 0,
firstName: 'Shi',
lastName: 'Xinxin'
}
2.2 使用
this.$store.state.count
3. mutations
3.1 声明
export default {
updateCount (state, num) {
state.count = num
}
}
3.2 使用
this.$store.commit('updateCount', i)
4. getters(类似组建中使用computed)
4.1 声明
export default {
fullName (state) {
return `${state.firstName} ${state.lastName}`
}
}
4.2 使用
this.$store.getters.fullName
5. 帮助方法
Component.vue
import {
mapState,
mapGetters
} from 'vuex'
export default {
computed: {
...mapState(['count']),
// or
...mapState({
counter: 'count'
}),
// or
...mapState({
counter: (state) => state.count
}),
... mapGetters(['fullName'])
}
}
三、Vuex之mutation和action
1. 文件夹结构
+ store
+ state
state.js
+ mutations
mutations.js
+ getters
getters.js
+ actions
actions.js
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import defaultState from './state/state.js'
import mutations from './mutations/mutation.js'
import getters from './getters/getters.js'
import actions from './actions/actions.js'
// 使用Router
Vue.use(Vuex)
export default () => {
return new Vuex.Store({
// 服务端渲染时会覆盖state,所以此时使用defaultState
state: defaultState,
// 操作与数据无关
mutations,
getters,
actions
})
}
2. mutation
专门修改state数据使用,但是可以直接在外部修改
必须是同步的操作,不可以有异步的代码
2.1 声明
只能有两个参数,第一个参数为state,第二个参数为一个object
export default {
updateCount (state, data) {
console.log(data.num1)
console.log(data.num2)
}
}
2.2 使用
this.$store.commit('updateCount', {
num1: 1,
num2: 2
})
3. action
修改state,异步代码
3.1 声明
只能有两个参数,第一个参数为state,第二个参数为一个object
export default {
updateCountAsync (state, data) {
setTimeout(() => {
store.commit('updateCount', data.num)
}, data.time)
}
}
3.2 使用
this.$store.dispach('updateCountAsync', {
num: 5,
time: 2000
})
4. 帮助方法
Component.vue
import {
mapState,
mapGetters,
mapActions,
mapMutations
} from 'vuex'
export default {
computed: {
...mapState(['count']),
// or
...mapState({
counter: 'count'
}),
// or
...mapState({
counter: (state) => state.count
}),
... mapGetters(['fullName'])
},
mounted () {
this.updateCountAsync({
num1: 1
num2: 2000
})
this.updateCount({
num1: 1,
num1: 2
})
},
methods: {
...mapActions(['updateCountAsync']),
...mapMutations(['updateCount'])
}
}
四、Vuex之模块
1. 文件夹结构
+ store
+ state
state.js
+ mutations
mutations.js
+ getters
getters.js
+ actions
actions.js
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import defaultState from './state/state.js'
import mutations from './mutations/mutation.js'
import getters from './getters/getters.js'
import actions from './actions/actions.js'
// 使用Router
Vue.use(Vuex)
export default () => {
return new Vuex.Store({
// 服务端渲染时会覆盖state,所以此时使用defaultState
state: defaultState,
// 操作与数据无关
mutations,
getters,
actions,
modules: {
a: {
state: {
text: 1
}
},
b: {
state: {
text: 2
}
}
}
})
}
2. State
2.1 声明
modules
index.js
export default () => {
return new Vuex.Store({
modules: {
a: {
state: {
text: 1
}
},
b: {
state: {
text: 2
}
}
}
})
}
2.2 使用
-
方法一:
this.$store.state.a.text
Component.vue
export default { computed: { textA () { return this.$store.state.a.text }, textB () { return this.$store.state.b.text } } }
-
方法二:
mapState
Component.vue
export default { computed: { ...mapState({ textA: state=>state.a.text textB: state=>state.b.text }) } }
3. Mutation
3.1 声明
modules
index.js
export default () => {
return new Vuex.Store({
modules: {
a: {
// 未声明方法放全局,声明后为命名空间内
namespaced: true,
state: {
text: 1
},
mutations: {
updateText (state, text) {
console.log('a.state', state)
state.text = text
}
}
},
b: {
state: {
text: 2
}
}
}
})
}
3.2 使用
mapMutations
Component.vue
export default {
mounted () {
// 未声明namespaced的话可以直接调用
this.updateText('123')
// 声明了namespaced的话要用变量形式
this['a/updateText']('123')
},
methods: {
// 未声明namespaced的话可以直接写名字
...mapMutations(['updateText']),
// 声明了namespaced的话要加命名空间名称
...mapMutations(['a/updateText'])
}
}
4. Getter
4.1 声明
modules
index.js
export default () => {
return new Vuex.Store({
modules: {
a: {
// 未声明方法放全局,声明后为命名空间内
namespaced: true,
state: {
text: 1
},
mutations: {
updateText (state, text) {
console.log('a.state', state)
state.text = text
}
},
getters: {
/**
* state: 当前命名空间下的state
* getters: 全局getters
* rootState: 根目录State,通过rootState可以得到全部state
*/
textPlus (state, getters, rootState) {
return state.text + rootState.b.text
}
}
},
b: {
state: {
text: 2
}
}
}
})
}
4.2 使用
mapGetters
Component.vue
export default {
mounted () {
console.log(this['a/textPlus'])
},
computed: {
...mapGetters(['a/textPlus'])
}
}
Component.vue
export default {
mounted () {
console.log(this.textPlus)
},
computed: {
...mapGetters({
textPlus: 'a/textPlus'
})
}
}
5. Action
5.1 声明
modules
index.js
export default () => {
return new Vuex.Store({
modules: {
a: {
// 未声明方法放全局,声明后为命名空间内
namespaced: true,
state: {
text: 1
},
mutations: {
updateText (state, text) {
console.log('a.state', state)
state.text = text
}
},
getters: {
/**
* state: 当前命名空间下的state
* getters: 全局getters
* rootState: 根目录State,通过rootState可以得到全部state
*/
textPlus (state, getters, rootState) {
return state.text + rootState.b.text
}
},
actions: {
// add (ctx) {
// ctx.state
// ctx.commit
// ctx.rootState
// }
add ({state, commit, rootState})
// updateText为本模块mutation,加上{root: true}可在全局寻找
commit (
'updateText',
rootState.count,
{root: true}
)
}
}
},
b: {
state: {
text: 2
},
actions: {
testAction ({commit}) {
commit(
'a/updateText',
'test'
)
}
}
}
}
})
}
5.2 使用
mapActions
Component.vue
export default {
mounted () {
this['a/add']()
},
methods: {
// 未声明namespaced的话可以直接写名字,声明了namespaced的话要加命名空间名称
...mapActions(['a/add', 'testAction'])
}
}
注: 模块可无限向下嵌套
6. 动态注册模块
6.1 声明
main.js
store.registerModule('c', {
state: {
text: 3
}
})
6.2 使用
Component.vue
export default {
computed: {
textC: state => state.c.text
}
}
7. 热更替(似乎存在问题,谨慎使用)
index.js
export default () => {
const store = new Vuex.Store({
state: defaultState,
mutations,
getters,
actions
})
if (module.hot) {
module.hot.accept([
'./state/state',
'./mutations/mutations'
'./actions/actions',
'./getters/getters'
], () => {
const newState = require('./state/state').default
const newMutations = require('./mutations/mutations').default
const newActions = require('./actions/actions').default
const newGetters = require('./getters/getters').default
store.hotUpdate({
state: newState,
mutations: newMutations,
actions: newActions,
getters: newGetters
})
})
}
return store
}
五、Vuex之其他一些API和配置
1. 注销模块
main.js
store.unregisterModule('c')
2. 监听state
main.js
store.watch(
// 相当于getter
(state) => {
state.count + 1
},
// 值发生变化时触发的回调函数
(newCount) => {
console.log('new count watched:', newCount)
}
)
3. 监听mutation
main.js
store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload);
})
4. 监听action
main.js
store.subscribeAction((action, state) => {
console.log(action.type)
console.log(action.payload);
})
5. 定制插件
index.js
export default () => {
const store = new Vuex.Store({
// 可以有多个插件,放入一个数组之中
plugins: [
// 利用上面三条组合进行私人订制
(store) => {
console.log('my plugin invoked')
},
...
]
})
return store
}