vuex最簡單、最直白、最全的入門文檔


前言

我們經常用element-ui做后台管理系統,經常會遇到父組件給子組件傳遞數據,下面一個簡單的例子,點擊按鈕,把彈框顯示變量數據通過子組件的props屬性傳遞,子組件通過$emit事件監聽把數據回傳給父組件。

父組件代碼:

<template>
  <div>
    <a href="javascript:;" @click="dialogshow = true">點擊</a>
    <common-dialog :show.sync="dialogshow"></common-dialog>
    彈框是否顯示:{{dialogshow}}
  </div>
</template>

<script>
import commondialog from '@/components/dialog'
export default {
    name: 'parent',
    components:{
        'common-dialog':commondialog
    },
    data () {
        return {
          dialogshow:false
        }
    },
    methods:{
        
    }
}
</script>

子組件代碼:

<template>
    <el-dialog :visible.sync="elDialogShow"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="elDialogShow = false">取 消</el-button>
            <el-button type="primary" @click="elDialogShow = false">確 定</el-button>
        </span>
    </el-dialog>
</template>
<script>
    export default {
        name:'children',
        props:['show'],
        computed:{
            elDialogShow:{
                get(){
                    return this.show
                },
                set(value){
                    this.$emit('update:show',value)
                }
            }
        },
        data() {
            return {
                
            };
        }
    }
</script>

 感覺這樣挺麻煩,父組件通過設置子組件的屬性(props)來向子組件傳遞數據,而父組件想獲得子組件的數據,得向子組件注冊事件,在子組件觸發這個事件再把數據傳遞出來。一句話總結起來就是,props 向下傳遞數據,事件向上傳遞數據

如果使用vuex,像下面這種方式就很簡單:

<!--父組件-->
<template>
  <div>
    <a href="javascript:;" @click="$store.state.show = true">點擊</a>
    <common-dialog></common-dialog>
    彈框是否顯示:{{$store.state.show}}
  </div>
</template>

<!--子組件-->
<el-dialog :visible.sync="$store.state.show"  title="提示">
    <!--其它代碼省略-->
</el-dialog>

 當然,在這兒舉這個例子似乎不恰當,只是為了說明vuex使用方便。

安裝使用vuex

安裝:

npm install vuex --save

main.js添加配置:

import vuex from 'vuex'
Vue.use(vuex)
var store = new vuex.Store({
    state:{
        show:false
    }
})
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

然后子組件代碼就能有效運行了。

<template>
    <el-dialog :visible.sync="$store.state.show"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.state.show = false">取 消</el-button>
            <el-button type="primary" @click="$store.state.show = false">確 定</el-button>
        </span>
    </el-dialog>
</template>
<script>
    export default {
        name:'children',
        data() {
            return {
                
            };
        }
    }
</script>

 modules

前面我們把store對象寫到了main.js中,為了項目的好管理,我們可以新建一個store文件夾放於src文件夾下,在store文件夾下新建index.js,代碼如下:

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex);

export default new vuex.Store({
    state:{
        show:false
    }
})

那么對應的main.js得改成如下:

//vuex
import store from './store'

new Vue({
  el: '#app',
  router,
  store,//使用store
  template: '<App/>',
  components: { App }
})

這樣雖然結構看着清晰了,但是如果多個模塊,不同類型(比如用戶基本信息,用戶購物車等)放到同一個state下面不好管理,這就用modules

那么store文件夾下的index.js就變成了這樣,假如我們有appuser模塊:

import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'   //app模塊數據
import user from './modules/user'  //用戶模塊數據
import getters from './getters'  

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    app,
    user
  },
  getters
})

export default store

getters

這兒說明下,上面我在Store實例對象中引入了getters,是為了后面頁面可以直接調用經常用到的狀態信息,也就相當於vue實例里面的computed計算屬性,通過$store.getters.show方式得到相關數據,即通過上面的getters引入知道,是直接在store文件夾下創建了一個getters.js,代碼如下:

const getters = {
  show: state => state.app.show
}
export default getters

當然這個getters也可以放到具體的模塊中,比如放到app模塊中,官網的這塊代碼結構如下:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

我們從index.js中看到,我們在store文件夾下創建了一個modules文件夾,也就是在該文件夾下放各個需要區分的狀態模塊,比如user.js,app.js等。

結構如下圖:

上面我們通過$store.getters.show方式(即相當於通過計算屬性)獲得show的值,當然也可以通過$store.state.app.show獲得。

app.js代碼:

export default {
    state:{
        show:false
    }
}

mutations

在我們點擊按鈕出現彈框或者點擊彈框中的關閉按鈕,需要修改app模塊中的show的狀態,這時候就需要通過mutations進行修改數據(同步操作)。

我們需要在app.js模塊代碼:

export default {
    state:{
        show:false
    },
 
    mutations:{
        SET_DIALOG_STATE:(state,val) => { //改變彈框是否顯示的狀態
            state.show = val
        }
    }
}

 父組件:

<template>
  <div>
    <a href="javascript:;" @click="$store.commit('SET_DIALOG_STATE',true)">點擊</a>
    <common-dialog></common-dialog>
    彈框是否顯示:{{$store.state.app.show}}
  </div>
</template>

<script>
import commondialog from '@/components/dialog'
export default {
    name: 'parent',
    components:{
        'common-dialog':commondialog
    },
    data () {
        return {
         
        }
    },
    
    methods:{
        
    }
}
</script>

子組件:

<template>
    <el-dialog :visible.sync="$store.getters.show"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.commit('SET_DIALOG_STATE',false)">取 消</el-button>
            <el-button type="primary" @click="$store.commit('SET_DIALOG_STATE',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>

這兒就是用到了$store.commit('SET_DIALOG_STATE',false)來觸發mutations中的SET_DIALOG_STATE方法來改變狀態值。

需要注意的是:

  • mutations中的方法是不分模塊的,比如你在app.js中定義了SET_DIALOG_STATE這個方法,也在user.js中定義了SET_DIALOG_STATE這個方法,那么在任一組件中調用$store.commit('SET_DIALOG_STATE',false),會執行所有的SET_DIALOG_STATE方法。
  • mutations里的操作必須是同步的。

如果在mutations 里執行異步操作會發生什么事情 , 實際上並不會發生什么奇怪的事情 , 只是官方推薦 , 不要在 mutations 里執行異步操作而已。

actions

我們在上面的app.js中通過mutations改變了一個狀態,那么如果需要改變多個狀態的值呢,需要執行mutations中定義的多個方法(也就是說需要調用多次$store.commit()方法),那么就需要actions

那么app.js代碼如需要改成如下:

export default {
    state:{
        show:false
    },
    getters:{
        showState(state){
            return state.show
        }
    },
    mutations:{
        SET_DIALOG_STATE:(state,val) => { //改變彈框是否顯示的狀態
            state.show = val
        }
    },
    actions:{
        set_dialog_state({commit,state},dialogVal){ //對象解構
            commit('SET_DIALOG_STATE',dialogVal)
            //commit('mutations其它方法','其它方法需要改變的值') 
        }
        
        //等價於下面的:
        /*
        set_dialog_state(context,dialogVal){
            context.commit('SET_DIALOG_STATE',dialogVal)
            context.commit('mutations其它方法','其它方法需要改變的值') 
        }
        */
    }
}

那么父組件的調用方式就需要用$store.dispatch()方法,父組件代碼如下:

<template>
  <div>
    <a href="javascript:;" @click="$store.dispatch('set_dialog_state',true)">點擊</a>
    <common-dialog></common-dialog>
    彈框是否顯示:{{$store.state.app.show}}
  </div>
</template>

<script>
import commondialog from '@/components/dialog'
export default {
    name: 'parent',
    components:{
        'common-dialog':commondialog
    },
    data () {
        return {
         
        }
    },
    
    methods:{
        
    }
}
</script>

子組件的代碼:

<template>
    <el-dialog :visible.sync="$store.getters.show"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.dispatch('set_dialog_state',false)">取 消</el-button>
            <el-button type="primary" @click="$store.dispatch('set_dialog_state',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>

這兒就使用$store.dispatch('set_dialog_state',true)來觸發actions中的set_dialog_state方法。官方推薦 , 將異步操作放在 action 中。

mapGetters、mapState、mapMutations、mapActions

很多時候 , $store.state.app.show$store.dispatch('set_dialog_state',true) 這種寫法又長又臭 , 很不方便 , 我們沒使用 vuex 的時候 , 獲取一個狀態只需要 this.show , 執行一個方法只需要 this.set_dialog_state就行了 , 使用 vuex 使寫法變復雜了 ?

使用 mapState、mapGetters、mapActions 就變得簡單了。

mapGetters

比如子組件原來是這樣:

<template>
    <el-dialog :visible.sync="$store.getters.show"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.dispatch('set_dialog_state',false)">取 消</el-button>
            <el-button type="primary" @click="$store.dispatch('set_dialog_state',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>

通過$store.getter.show得到狀態值,我們也可以這樣:

<template>
    <el-dialog :visible.sync="show"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.dispatch('set_dialog_state',false)">取 消</el-button>
            <el-button type="primary" @click="$store.dispatch('set_dialog_state',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>
<script>
    import { mapGetters } from 'vuex'
    export default {
        name:'children',
        data() {
            return {
                
            };
        },
        computed:{
            ...mapGetters([
                'show'
            ])
        }
        
    }
</script>

mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性。

當然我們也可以給getters里面的狀態show換一個名字,比如叫dialogShow,那么子組件就需要改成如下:

<template>
    <el-dialog :visible.sync="dialogShow"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.dispatch('set_dialog_state',false)">取 消</el-button>
            <el-button type="primary" @click="$store.dispatch('set_dialog_state',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>
<script>
    import { mapGetters } from 'vuex'
    export default {
        name:'children',
        data() {
            return {
                
            };
        },
        computed:{
            ...mapGetters({
                dialogShow:'show'
            })
        }
        
    }
</script>

mapState

上面我們通過$store.getters.show拿到狀態值,我們也可以通過$store.state.app.show拿到值,那么怎樣使用mapState呢?

子組件寫法:

<template>
    <el-dialog :visible.sync="show"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.dispatch('set_dialog_state',false)">取 消</el-button>
            <el-button type="primary" @click="$store.dispatch('set_dialog_state',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>
<script>
    import { mapState } from 'vuex'
    export default {
        name:'children',
        data() {
            return {
                
            };
        },
        computed:{
            ...mapState({
                show:state => state.app.show
            })
        }
        
    }
</script>

上面使用的是箭頭函數,也可以使用常規函數,如下:

<template>
    <el-dialog :visible.sync="showState"  title="提示">
        <span>這是一段彈框信息</span>
        <span slot="footer" class="dialog-footer">
            <el-button @click="$store.dispatch('set_dialog_state',false)">取 消</el-button>
            <el-button type="primary" @click="$store.dispatch('set_dialog_state',false)">確 定</el-button>
        </span>
    </el-dialog>
</template>
<script>
    import { mapState } from 'vuex'
    export default {
        name:'children',
        data() {
            return {
                
            };
        },
        computed:{
            ...mapState({
                show:state => state.app.show, //方式一 箭頭函數
                showState(state){  //方式二 常規函數
                    return state.app.show
                }
            })
        }
        
    }
</script>

mapMutations

你可以在組件中使用 $store.commit('xxx') 提交 mutation,或者使用 mapMutations 輔助函數將組件中的 methods 映射為 store.commit 調用

父組件代碼如下:

<template>
  <div>
    <a href="javascript:;" @click="SET_DIALOG_STATE(true)">點擊</a>
    <common-dialog></common-dialog>
    彈框是否顯示:{{$store.state.app.show}}
  </div>
</template>

<script>
import { mapMutations } from 'vuex'
import commondialog from '@/components/dialog'
export default {
    name: 'parent',
    components:{
        'common-dialog':commondialog
    },
    data () {
        return {
         
        }
    },
    
    methods:{
        ...mapMutations(['SET_DIALOG_STATE'])
    }
}
</script>

給方法名換個名字:

<template>
  <div>
    <a href="javascript:;" @click="changeState(true)">點擊</a>
    <common-dialog></common-dialog>
    彈框是否顯示:{{$store.state.app.show}}
  </div>
</template>

<script>
import { mapMutations } from 'vuex'
import commondialog from '@/components/dialog'
export default {
    name: 'parent',
    components:{
        'common-dialog':commondialog
    },
    data () {
        return {
         
        }
    },
    
    methods:{
        ...mapMutations({
            changeState:'SET_DIALOG_STATE' //改變名字
        })
    }
}
</script>

mapActions

你在組件中使用$store.dispatch('xxx') 分發 action,或者使用 mapActions 輔助函數將組件的 methods 映射為 store.dispatch 調用

父組件代碼:

<template>
  <div>
    <a href="javascript:;" @click="set_dialog_state(true)">點擊</a>
    <common-dialog></common-dialog>
    彈框是否顯示:{{$store.state.app.show}}
  </div>
</template>

<script>
import { mapActions  } from 'vuex'
import commondialog from '@/components/dialog'
export default {
    name: 'parent',
    components:{
        'common-dialog':commondialog
    },
    data () {
        return {
         
        }
    },
    
    methods:{
        ...mapActions (['set_dialog_state'])
    }
}
</script>

當然也可以換方法名,這兒就不貼代碼了。

參考地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM