介紹
vuex是一種狀態(tài)管理模式传于,它保存著組件的公用的狀態(tài)碉克,并且以相應(yīng)的規(guī)則保證狀態(tài)變化。
vuex的核心就是一個(gè)store赁还,它相當(dāng)于是一個(gè)容器妖泄,里面包含有state,action,mutation,getter,modules。
state:用于數(shù)據(jù)的存儲(chǔ)艘策,是store中的唯一數(shù)據(jù)源
getters:如vue中的計(jì)算屬性一樣蹈胡,基于state數(shù)據(jù)的二次包裝,常用于數(shù)據(jù)的篩選和多個(gè)數(shù)據(jù)的相關(guān)性計(jì)算
mutation:類似函數(shù)朋蔫,改變state數(shù)據(jù)的唯一途徑罚渐,且不能用于處理異步事件
action:類似于mutation,用于提交mutation來改變狀態(tài)驯妄,而不直接變更狀態(tài)荷并,可以包含任意異步操作
modules:類似于命名空間,用于項(xiàng)目中將各個(gè)模塊的狀態(tài)分開定義和操作青扔,便于維護(hù)
特點(diǎn)
Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的源织。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候翩伪,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新谈息。
你不能直接改變 store 中的狀態(tài)缘屹。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化侠仇,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用囊颅。
vuex是單一狀態(tài)樹
vuex的流程
vuex的整體流程是:
在組件內(nèi)部,通過dispatch來分發(fā)action傅瞻。
再通過action來第調(diào)用mutation
進(jìn)而觸發(fā)mutation內(nèi)部的commit來修改state
最后state改變踢代,導(dǎo)致頁面重新render。
使用
vuex的使用場(chǎng)景
大型應(yīng)用中嗅骄,用于全局共享的data,例如全局消息提醒平酿、控件權(quán)限控制等等碌冶。
vuex可配合sessionStorage做用戶基本信息的持久化存儲(chǔ)衅谷。
多級(jí)組件的數(shù)據(jù)需要共享或多個(gè)頁面之間的數(shù)據(jù)存在因果關(guān)系時(shí)淘邻,可以使用vuex。
在state中定義了count屏积、userInfo医窿、students三個(gè)屬性,state里面的數(shù)據(jù)狀態(tài)可以在全局中被訪問,在任意組件中通過this.$store.state.attrName訪問炊林,在demo.vue的computed屬性里面姥卢,我們獲取了以上三個(gè)屬性
getter中可以自定義一些函數(shù)對(duì)state屬性里面的數(shù)據(jù)進(jìn)行過濾,并且在任意組件中可以通過this.$store.gettter.functionName的方式獲取
mutaions用來更新state里面的狀態(tài)渣聚,我們可以定義一些方法對(duì)數(shù)據(jù)進(jìn)行操作独榴,在里面的方法中至少有state和value兩個(gè)參數(shù),state就是上面所說的state對(duì)象(屬性)奕枝,value就是從組件傳遞來的值棺榔。可以看到隘道,在demo.vue中點(diǎn)擊加號(hào)按鈕或者減號(hào)按鈕症歇,通過this.$store.commit('getUserInfo',count的方式向vuex提交了一個(gè)事件,在store.js中mutaions里面的updateCount將提交過值接收并進(jìn)行處理谭梗,state里面的count狀態(tài)被更新忘晤,這是demo組件的computed屬性中的number被執(zhí)行,然后緊接著dom被更新默辨。
actions也是對(duì)state狀態(tài)進(jìn)行更新德频,但是是間接的苍息,一些異步的操作先交給actions里面的函數(shù)執(zhí)行缩幸,拿到結(jié)果后在交給mutaions中相應(yīng)的處理函數(shù)處理壹置,接下來的操作就跟上面講的一樣。 點(diǎn)擊獲取用戶信息按鈕表谊,通過this.$store.dispatch('getUserInfo',this)向vuex提交了一個(gè)事件钞护,store.js中actions的getUserInfo函數(shù)處理了這個(gè)事件,向本地一個(gè)user.json文件發(fā)了一個(gè)異步請(qǐng)求爆办,難道結(jié)果后將返回的用戶信息交給了mutaions的getUserInfo函數(shù)處理难咕,state的userInfo屬性被改變,userInfo的變化導(dǎo)致demo.vue中computed屬性的userInfo被執(zhí)行距辆,接著dom更新余佃,用戶信息被顯示。
代碼如下:
// store/store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
count:0,
userInfo:{},
students:[]
},
getters:{
},
mutations:{
updateCount(state,count){
state.count = count
},
getUserInfo(state,userInfo){
state.userInfo = userInfo
},
getStudents(state,students){
state.students = students
}
},
actions:{
updateCountAsync({commit,state},count){
setTimeout(function() {
console.log('count:'+count)
commit('updateCount',count)
}, 1000);
},
getUserInfo({commit,state},_this){
let _vm = _this
console.log(_vm)
_vm.$http.get('http://localhost:8080/static/data/user.json').then(res=>{
console.log(res)
commit('getUserInfo',res.data)
})
},
getStudents({commit,state},_this){
let _vm = _this
_vm.$http.get('/api/students').then(res=>{
console.log(res)
commit('getStudents',res.data.data.students)
})
}
}
})
// demo.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div class="number-box" style="margin:20px 0;">
<button @click="plus">加 一</button>
<input type="text" v-model="number" style="padding-left:20px;">
<button @click="minus">減 一</button>
</div>
<button @click="getUserInfo">獲取用戶信息</button>
<div class="user-info" v-if="userInfo">
<span class="name" >{{userInfo.name}}</span>
<span class="gender" >{{userInfo.gender}}</span>
<span class="age">{{userInfo.age}}</span>
</div>
<button @click="getStudentList">獲取成績榜單</button>
<div v-if="students.length>0">
<h4 >成績榜單</h4>
<ul>
<li v-for="item in students" :key="item.id">
<span>{{item.name}}</span>
<span>{{item.score}}</span>
</li>
</ul>
</div>
</div>
</template>
<style>
</style>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
mounted() {
},
computed:{
number(){
return this.$store.state.count
},
userInfo(){
return this.$store.state.userInfo
},
students(){
return this.$store.state.students
}
},
methods:{
plus(){
// this.number++
let count = Number(this.number)+1
console.log('plus:'+count)
this.$store.dispatch('updateCountAsync',count)
},
minus(){
// this.number--
let count = Number(this.number)-1
console.log('minus:'+count)
this.$store.dispatch('updateCountAsync',count)
},
getUserInfo(){
this.$store.dispatch('getUserInfo',this)
},
getStudentList(){
this.$store.dispatch('getStudents',this)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
.user-info{
margin-top:20px;
margin-bottom:20px;
}
.name{
color:blue;margin-right:20px
}
.gender{
color:red;margin-right:20px
}
.age{
color:blue;margin-right:20px
}
</style>