本文取之官網和其他文章結合自己的理解用簡單化的語言表達。用於自己的筆記記錄,也希望能幫到其他小伙伴理解,學習更多的前端知識。
-
Vuex 是什么?
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
官方文檔: https://vuex.vuejs.org/zh/
簡單的說,這個vuex可以用於存儲數據的狀態。例如:
我的個人信息是否完善的這個狀態,可以存儲在vuex中,在不同的頁面可以讀取、更改這個狀態。這樣就不用頁面之間傳參等方式。
當然也可以存儲一些信息,例如數組、對象、字符串都可以,類似前端的數據庫。如果只有這個特點的話,有的小伙伴會有疑問,那本地存儲也可以做到的,現在我們就看一下vuex與本地存儲的區別。
1.區別:vuex存儲在內存,localstorage(本地存儲)則以文件的方式存儲在本地,永久保存;sessionstorage( 會話存儲 ) ,臨時保存。localStorage和sessionStorage只能存儲字符串類型,對於復雜的對象可以使用ECMAScript提供的JSON對象的stringify和parse來處理
2.應用場景:vuex用於組件之間的傳值,localstorage,sessionstorage則主要用於不同頁面之間的傳值。
3.永久性:當刷新頁面(這里的刷新頁面指的是 --> F5刷新,屬於清除內存了)時vuex存儲的值會丟失,sessionstorage頁面關閉后就清除掉了,localstorage不會。
注:很多同學覺得用localstorage可以代替vuex, 對於不變的數據確實可以,但是當兩個組件共用一個數據源(對象或數組)時,如果其中一個組件改變了該數據源,希望另一個組件響應該變化時,localstorage,sessionstorage無法做到,原因就是區別1
原始網址:https://blog.csdn.net/sinat_36729274/article/details/87433615
- vuex安裝
安裝命令行:npm install vuex --save

安裝成功后,使用命令行:npm run dev 運行項目。接下來會在項目中使用vuex,首先,在src文件夾下新建一個名為store的文件夾,在store文件夾下新建index.js文件,index.js文件的內容分為:
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
// 使用vuex
Vue.use(Vuex)
// 創建vuex實例
const store = new Vuex.Store({
})
export default store
然后在main.js文件中引入store文件夾下的index.js文件。main.js文件中內容如下:
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store' // ------------ 引入store文件夾下面的index.js
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
store, // -------------- 將store 添加到vue的實例中
router,
components: { App },
template: '<App/>'
})
這樣我們就在項目中引入vuex了,那怎么使用vuex呢?
vuex的核心概念是以下幾個:
-
- State
- Getter
- Mutation
- Action
- Module
下面是具體來講一下vuex核心概念的使用方法吧。
- State
Vuex 使用單一狀態樹——是的,用一個對象就包含了全部的應用層級狀態。至此它便作為一個“唯一數據源 (SSOT)”而存在。這也意味着,每個應用將僅僅包含一個 store 實例。單一狀態樹讓我們能夠直接地定位任一特定的狀態片段,在調試的過程中也能輕易地取得整個當前應用狀態的快照。
以上是官網的說法,我的理解就是在state中聲明變量,可以在全部頁面都可以使用state中的變量。
現在,我們開始新建和使用state,在store文件夾下面新建state文件夾,state文件夾下面新建index.js文件,index.js文件內容如下:
const state = {
name: 'weish',
age: 22,
todos: [
{ id: 1, text: '1111', done: true },
{ id: 2, text: '2222', done: false }
]
};
export default state;
然后將state引入到store中,所以在store文件夾下的index.js內容如下:
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
import state from './state' // ---------引入state
// 使用vuex
Vue.use(Vuex)
// 創建vuex實例
const store = new Vuex.Store({
state // ---------將state添加到實例中
})
export default store
做完上面state中的聲明與store中的引入,我們就可以在頁面中使用state中的變量了。
HelloWorld.vue內容如下:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>state:方法一:{{this.$store.state.age}}</h2>
<h2>state:方法二:{{age2}}</h2>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
age2(){
return this.$store.state.age
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
使用輔助函數mapState時,HelloWorld.vue內容如下:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>state:方法一:{{this.$store.state.age}}</h2>
<h2>state:方法二:{{age2}}</h2>
<h2>state:方法三:{{age3}}</h2>
<h2>state:方法四:{{age4}}</h2>
</div>
</template>
<script>
// 輔助函數為 Vuex.mapState
import { mapState } from 'vuex'
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed: mapState({
age2: 'age', //方法2
age3: (state) => state.age, // 方法3
age4:function () {
return this.$store.state.age // 普通函數的使用store的方式,方法4
}
})
//沒有使用mapState時,普通函數的寫法
// computed:{
// age5(){
// return this.$store.state.age //方法5
// },
// ...mapState(['name','age']) // 方法6
// }
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
頁面效果如下:

- Getter
有時候我們需要從 store 中的 state 中派生出一些狀態,例如對列表進行過濾並計數:
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
如果有多個組件需要用到此屬性,我們要么復制這個函數,或者抽取到一個共享函數然后在多處導入它——無論哪種方式都不是很理想。
Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。
在store文件夾下新建getters文件夾,在getters文件夾下新建index.js,內容如下:
export const doneTodosCount = (state) => {
return state.todos.filter(todo => todo.done).length;
}
在store文件夾下index.js中引入getters
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
import state from './state'
import * as getters from './getters' // ---------引入
// 使用vuex
Vue.use(Vuex)
// 創建vuex實例
const store = new Vuex.Store({
state,
getters // --------添加
})
export default store
可以通過屬性訪問:store.getters.doneTodosCount
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>getters: {{Count}}</h2>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
Count() {
return this.$store.getters.doneTodosCount // -------1
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
頁面效果如下:

使用輔助函數mapGetters,內容如下:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>getters: {{Count}}</h2>
<h2>getters:mapGetters {{doneTodosCount}}</h2> // -----------頁面中{{doneTodoCount}}
</div>
</template>
<script>
// 在單獨構建的版本中輔助函數為 Vuex.mapState 和mapGetter
import { mapState,mapGetters } from 'vuex' // -----引入mapGetters
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
age(){
return this.$store.state.age
},
...mapState(['name','age','todos']),
...mapGetters(['doneTodosCount']), //-----------在computed使用mapGetter
Count() {
return this.$store.getters.doneTodosCount
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
- Mutation
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。mutations必須是同步函數。
在store文件夾下新增mutations文件夾,在mutations文件夾下新增index.js,內容如下:
export const CACHE_AGE = (state, param) => { // 當提交格式是簡單數據格式,例如:123,'123'
state.age += param;
}
export const newName = (state,payload) => { // 當提交格式是對象格式
state.name = payload.newName
}
在store文件夾下index.js中引入mutations
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
import state from './state'
import * as getters from './getters'
import * as mutations from './mutations' // -----------引入mutations
// 使用vuex
Vue.use(Vuex)
// 創建vuex實例
const store = new Vuex.Store({
state,
getters,
mutations // ---------添加到實例
})
export default store
在頁面中使用mutations修改state中age
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>state:方法一:{{this.$store.state.age}}</h2>
<h2>getters: {{Count}}</h2>
<h2>getters:mapGetters {{doneTodosCount}}</h2>
<div><button @click="plus()">點我age加2</button></div>
<h2>{{name}}</h2>
<div><button @click="changeName()">點我name修改為Alise</button></div>
</div>
</template>
<script>
// 在單獨構建的版本中輔助函數為 Vuex.mapState
import { mapState,mapGetters } from 'vuex'
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
age(){
return this.$store.state.age
},
...mapState(['name','age','todos']),
...mapGetters(['doneTodosCount']),
Count() {
return this.$store.getters.doneTodosCount
}
},
methods:{
plus(){
this.$store.commit('CACHE_AGE', 2)
},
changeName(){
// this.$store.commit({type:'newName',newName:'Alise'}) //--------------對象風格提交格式 方法一
this.$store.commit('newName',{newName:'Alise'}) // -------------對象風格提交格式 方法二
}
}
}
</script>
-
- 使用常量替代Mutation事件類型
把這些常量放在單獨的文件中可以讓你的代碼合作者對整個 app 包含的 mutation 一目了然。用不用常量取決於你——在需要多人協作的大型項目中,這會很有幫助。但如果你不喜歡,你完全可以不這樣做。
在mutations文件夾下面新建mutation-types.js,內容如下:
export const CACHE_NAME_TYPE = 'CACHE_NAME_TYPE'
mutations文件夾下index.js,內容如下:
import { CACHE_NAME_TYPE } from './mutation-types'
const mutations = {
[CACHE_NAME_TYPE](state,payload){
state.name = payload.newName
}
}
export default mutations
// ps:如果mutation部分寫成這種格式,那么在store文件夾下的index.js中引入mutations的方式需要修改寫成
// import mutations from './mutations'
// 而不是 import * as mutations from './mutations'
在頁面中使用mapMutations輔助函數:
<template>
<div class="hello">
<h1>{{ msg }}</h1
<h2>state:name:{{name}}</h2>
<div><button @click="changeName()">點我store的名字變成alise</button></div>
<div><button @click="changeName1()">點我store的名字變成Mark</button></div>
</div>
</template>
<script>
// 在單獨構建的版本中輔助函數為 Vuex.mapState
import { mapState,mapGetters,mapMutations } from 'vuex' // ------引入mapMutation
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
...mapState(['name','age','todos']),
...mapGetters(['doneTodosCount'])
},
methods:{
...mapMutations(['CACHE_NAME']), // -------------在methods中映射,將this.CACHE_NAME()映射為this.$store.commit('CACHE_NAME')
changeName(){
this.$store.commit('newName',{newName:'Alise'})
},
changeName1(){
this.CACHE_NAME({newName:'MARK'}) // -------使用
}
}
}
</script>
- Action
action類似mutation,不同之處在於:
-
- action提交的mutation,而不是直接改變的狀態
- action可以包含任一異步操作
在store文件夾下新建actions文件夾,actions文件夾下新建index.js,內容如下:
export const setName = ({ commit }, param) => {
commit('CACHE_NAME', param)
}
在store文件夾下的index.js中引入actions

就可以在頁面中使用actions了,在頁面中調用actions的方法是:this.$store.dispatch('setName',{newName:'Tom'}),具體代碼如下:
<template>
<div class="hello">
<h1>{{ msg }}</h1
<h2>state:name:{{name}}</h2>
<div><button @click="changeName()">點我store的名字變成alise</button></div>
<div><button @click="changeName1()">點我store的名字變成Mark</button></div>
<div><button @click="changeName2()">點我store的名字通過actions方式變成Tom</button></div>
</div>
</template>
<script>
import { mapState,mapGetters,mapMutations } from 'vuex'
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
...mapState(['name','age','todos']),
...mapGetters(['doneTodosCount'])
},
methods:{
...mapMutations(['CACHE_NAME']),
changeName(){
this.$store.commit('newName',{newName:'Alise'})
},
changeName1(){
this.CACHE_NAME({newName:'MARK'})
},
changeName2(){
this.$store.dispatch('setName',{newName:'Tom'})
}
}
}
</script>
使用mapActions輔助函數:
<template>
<div class="hello">
<h1>{{ msg }}</h1
<h2>state:name:{{name}}</h2>
<div><button @click="changeName()">點我store的名字變成alise</button></div>
<div><button @click="changeName1()">點我store的名字變成Mark</button></div>
<div><button @click="changeName2()">點我store的名字通過actions方式變成Tom</button></div>
</div>
</template>
<script>
import { mapState,mapGetters,mapMutations,mapActions } from 'vuex' // ------------添加mapActions
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
...mapState(['name','age','todos']),
...mapGetters(['doneTodosCount'])
},
methods:{
...mapMutations(['CACHE_NAME']),
...mapActions(['setName']), // 修改二:在methods中添加...mapActions
changeName(){
this.$store.commit('newName',{newName:'Alise'})
},
changeName1(){
this.CACHE_NAME({newName:'MARK'})
},
changeName2(){
// this.$store.dispatch('setName',{newName:'Tom'})
this.setName({newName:'Tom1111'}) // 修改三:使用this.setName提交修改mutation
}
}
}
</script>
actions中通常是異步操作,可以組合使用action,以處理更復雜的流程。可查看官網例子組合action,官網地址:https://vuex.vuejs.org/zh/guide/actions.html
- Modules
由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的對象。當應用變得非常復雜時,store 對象就有可能變得相當臃腫。
為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module)。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割。官方地址:https://vuex.vuejs.org/zh/guide/modules.html。
在store文件夾下,新建modules文件夾,在modules文件夾下面新建moduleA.js文件,內容如下:
const moduleA = {
state: { count: 0 },
mutations: {
increment (state,num) {
// 這里的 `state` 對象是模塊的局部狀態
state.count += num
}
},
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.age
}
},
actions:{
incrementIfOddOnRootSum ({ state, commit, rootState },param) {
console.log(state,rootState,param) // state :局部state傳入值,如:{count:0},rootState:根元素state傳入值,param:外部傳入參
commit('increment',param.num)
}
}
}
export default moduleA
在store文件夾下index.js文件中,引入moduleA.js,內容如下:
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
import state from './state'
import * as getters from './getters'
import * as mutations from './mutations'
import * as actions from './actions'
// import mutations from './mutations'
// moudules
import mouduleA from './modules/moduleA' // --------引入moduleA
// 使用vuex
Vue.use(Vuex)
// 創建vuex實例
const store = new Vuex.Store({
state,
getters,
mutations,
actions,
modules:{
a:mouduleA // -----------實例化
}
})
export default store
在頁面中使用moduleA,helloword.vue內容如下:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>mouduleA--count:{{a.count}}</h2> // 使用mapState在頁面中顯示,也可直接寫 this.$store.state.a.count
<h2>moduleA--sumWithRootCount:{{sumWithRootCount}}</h2> // 使用mapGetters
<div><button @click="changeCount()">點我ModuleA的Count+某個數</button></div>
</div>
</template>
<script>
// 在單獨構建的版本中輔助函數為 Vuex.mapState
import { mapState,mapGetters,mapMutations,mapActions } from 'vuex' // -------引入mapState,mapGetters,mapMutations,mapActions
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
...mapState(['a']), // 在computed中 --------------使用mapState
...mapGetters(['sumWithRootCount']), // computed中-----------使用mapGetters
Count() {
return this.$store.getters.doneTodosCount
}
},
methods:{
...mapMutations(['increment']), // 在methods中-----------使用mapMutations
...mapActions(['incrementIfOddOnRootSum']), // 在methods中---------使用mapActions
changeCount(){
// this.$store.commit('increment',11) // ------------一般方法 mutation 修改moduleA中state中的值
// this.$store.dispatch('incrementIfOddOnRootSum',{num:12}) // --------------一般方法 action 提交mutation
// this.increment(12) // ----------使用mapMutations 修改moduleA中state的值
this.incrementIfOddOnRootSum({num:10}) // ------------使用mapActions 提交mutations
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
- store文件夾目錄
store文件夾下,經過上述的關於核心概念的介紹,新建了actions、getters、state、mutations和modules五個文件夾,除modules文件夾下面是moduleA.js之外,其他下面都是index.js文件。第一圖是store文件夾下的目錄,中圖是展開后,當然也可以根據自己的習慣管理文件。例如第三圖。



ok,上述代碼均經過本人測試,如果有問題,歡迎留言。
