一、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
}