Vuex基礎(chǔ)使用和雙向綁定

Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。

1. Vuex介紹

Vuex是官方的狀態(tài)管理工具枕扫,主要概念有State陪腌、Getter、Mutation铡原、Action偷厦、Module。
文章的開頭說過Vue的組件都是一個個Vue實例燕刻,Vuex也可以這樣來看,具體對比關(guān)系如下:

Vuex 主要作用 Vue組件
State 用來保存狀態(tài) 相當(dāng)于data屬性
Getter 用來對屬性進行組合修改 相當(dāng)于計算屬性
Mutation 常用來直接改變State的值 相當(dāng)于methods
Action 主要用于提交Mutations,并且可以處理異步 -
Module 用于模塊化狀態(tài)管理 模塊化Vue組件

使用Vuex只泼,我們用State保存狀態(tài),使用Getter來對狀態(tài)數(shù)據(jù)進行處理卵洗,使用Mutation來直接改變State的值请唱,用Action來提交Mutation,Action不是另類的Mutation,他操作的是Mutation中的函數(shù)过蹂,按照規(guī)范十绑,Action是不能直接修改State的,雖然它可以修改State酷勺,如果需要返回一個狀態(tài)或者一個異步的回調(diào)本橙,比如在Actions里面進行了http請求,可以直接返回一個Promise脆诉,使用Module,來對龐大的項目進行分組甚亭。

2. 對Vuex中State的獲取

一般情況下都會把Vuex全局注入到Vue中贷币,這時每一個Vue實例都能訪問到,一般都會使用計算屬性來接受Vuex的值亏狰,代碼如下:

//定義一個簡單的Vuex
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
      Title: "123",
  },
  mutations: {
    changeTitle(state, newTitle) {
      state.Title= newTitle;
    },
  },
});

//組件中使用
<template>
<div class="test">{{NewState}}</div>
</template>
<script>
export default {
  computed: {
  NewState(){
    return this.$store.state.Title
  }
  },
//其他必要代碼
}
</script>

這樣就能夠在頁面上顯示Vuex中的Title值了役纹。

除此之外還有一個輔助函數(shù),在本例子中代碼改為:

//組件中使用
<template>
<div class="test">{{Title}}</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
  computed: {
 ...mapState(['Title']),
  },
//其他必要代碼
}
</script>

3. 對Vuex中State的改變

在上述Vuex例子中已經(jīng)聲明了Mutation,只需要把代碼改為:

//組件中使用
<template>
<input type="text" v-model="newTitle">
<div class="test">{{Title}}</div>
<button @click="changeTitle">改變Vuex中的title</button>
</template>
<script>
import { mapState } from 'vuex'
export default {
  data(){
  return{
  newTitle:"",
  } },
  computed: {
 ...mapState(['Title']),
  },
 methods:{
 chageTitle(){
  this.$store.commit('changeTitle',this.newTitle)
 },
},
//其他必要代碼
}
</script>
4.gif

上述代碼主要是添加了一個輸入框和一個按鈕暇唾,輸入框輸入數(shù)據(jù)后促脉,點擊改變按鈕,就會觸發(fā)一個點擊事件策州,這個點擊事件中出發(fā)函數(shù)瘸味,函數(shù)調(diào)用Vuex中Mutation中的方法changeTitle,并傳過去了文本框中的值抽活,Mutation中的changeTitle則改變了State中的Title的值硫戈,因為組件中獲取Vuex的值使用計算屬性锰什,因此也會同步到頁面下硕。

當(dāng)然Mutation也有輔助函數(shù),只需在上面修改代碼如下:

//組件中使用
<template>
<input type="text" v-model="newTitle">
<div class="test">{{Title}}</div>
<button @click="changeTitles">改變Vuex中的title</button>
</template>
<script>
import { mapState,mapMutations } from 'vuex'
export default {
  data(){
  return{
  newTitle:"",
  } },
  computed: {
 ...mapState(['Title']),
  },
 methods:{
    ...mapMutations(['changeTitle']),
    changeTitles() {
      this.changeTitle(this.newTitle)
    },
    // changeTitle() {
    //   this.$store.commit('changeTitle', this.newTitle)
    // },
},
//其他必要代碼
}
</script>

4. Vuex中State的雙向綁定

Vuex的State的雙向綁定通常用在 form表單汁胆,當(dāng)然也有其他需要雙向綁定的情況梭姓。
本小節(jié)主要應(yīng)用技術(shù)是Vue計算屬性的get方法和set方法,對上面例子修改后,代碼如下:

export default {
 computed: {
    newTitle: {
      get() {
        return this.$store.state.Title;
      },
      set(value) {
        this.$store.commit('changeTitle', value)
      }
    }
  },
}

把提交修改的事件添加到計算屬性的set方法中嫩码,就可以在值改變的時候觸發(fā)修改操作誉尖,從而改變State的值,這個操作在form表單中是可以行得通的铸题,因為表單一般用v-model綁定數(shù)據(jù)铡恕,而v-model是一個語法糖,它內(nèi)部擁有input事件丢间,可以觸發(fā)計算屬性的set方法探熔,而不用v-model的時候則不能觸發(fā)計算屬性的set方法,也就無法實現(xiàn)雙向綁定烘挫,這時候需要使用監(jiān)聽器監(jiān)聽newTitle值的變化诀艰,從而觸發(fā)改變State的Mutation方法,代碼如下:

export default {
 computed: {
    newTitle(){
      return this.$store.state.Title;
    }
  },
 watch:{
   newTitle(newd,oldd){
     this.$store.commit('changeTitle', newd)
   }
 }
}

因為監(jiān)聽器是在數(shù)據(jù)發(fā)生變化時執(zhí)行的饮六,所以能夠解決非v-model指令不能觸發(fā)set方法的問題其垄。

5. Vuex中對象屬性的深層監(jiān)聽

本小節(jié)是對上個小節(jié)的一點拓展。
在對Vuex的日常使用中卤橄,一般都不會一個屬性設(shè)置一個值绿满,一般都會進行分組,而模塊過大的時候就會啟用Vuex的Module窟扑,在一個設(shè)置配置的Vuex中喇颁,一般有如此配置:

//系統(tǒng)設(shè)置
    config: {
      events: true,
      calls: false,
      messages: false,
      notifications: false,
      sounds: false,
      videoSounds: false
    }

我們在組件中使用則會這樣用:

<script>
import { mapState } from 'vuex'
export default {
  name: 'Drawer',
  data() {
    return {
      docked: false,
      position: 'left'
    }
  },
  computed: {
      ...mapState(['config'])
   }
}
</script>

在組件中就會使用v-model="config.events"來使用寄月,這明顯是使用了v-model的對象賦值,但是計算屬性并不會檢測內(nèi)部的變化无牵,從而觸發(fā)set方法漾肮,去提交對State修改的Mutation方法。
使用Vue的監(jiān)聽器設(shè)置deep:true茎毁,監(jiān)聽器默認也不會監(jiān)聽內(nèi)部變化克懊,設(shè)置deeptrue可以監(jiān)聽內(nèi)部變化,代碼如下:

<script>
import { mapState } from 'vuex'
export default {
 computed: {
     ...mapState(['config']),
   },
  watch: {
    config: {
      handler(newValue, oldValue) {
        this.$store.commit('changeConfig', newValue)
      },
      deep: true
    },
  },
}
</script>

這樣就對config的值進行了深層雙向綁定七蜘,而不是重復(fù)書寫這幾個配置屬性的getset方法

6. Getter

前文提到過谭溉,Getter就像計算屬性。比如一個列表屬性橡卤,有時我們只需要其中一條數(shù)據(jù)我們可以這樣做:

export default new Vuex.Store({
  state: {
    list: [
      { id: 1, text: '我是1'},
      { id: 2, text: '我是2'}扮念,
      { id: 3, text: '我是3'}
    ]
  },
  getters: {
    getone: state => {
      return state.list.filter(id=> id===1)
    }
  }
})

這樣調(diào)用時,就只會返回第一條數(shù)據(jù)碧库。
在組件中使用:

computed: {
 getOnes () {
    return this.$store.getters.getone
  }
}

值得注意的是柜与,雖然Vuex中Geeter類似于組件中的計算屬性,但是Getter并沒有像計算屬性那樣混入實例(按照計算屬性類比的話嵌灰,Vuex調(diào)用Getter需要使用this.$store.state.getone)弄匕,但是Getter調(diào)用還是要this.$store.getters.getone

同樣可以使用助手函數(shù):

computed: {
    ...mapGetters([
      'getone'
    ])
  }

7. Action

Action是Vuex中的異步調(diào)用解決方法沽瞭,因為Mutation只能使用同步方法迁匠,Action操作的是Mutation中的函數(shù),下面有一個例子:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state) {
      state.count+=1
    }
  },
  actions: {
    increment (context) {
      context.commit('add')
    }
  }
})

在使用的時候可以這樣操作:

export default {
 methods:{
 addCount(){
  this.$store.dispatch('add')
 },
},
//其他必要代碼
}

同樣可以使用助手函數(shù):

import { mapActions } from 'vuex'
export default {
 methods:{
 ...mapActions(['add']),
},
//其他必要代碼
}

如果需要在Action中傳遞值需要繞一下驹溃,代碼如下:

import { mapActions } from 'vuex'
export default {
 data(){
  return{
    value:'',
  };
 },
methods: {
    changeTitles() {
      this.$store.dispatch('change',value)
    },
//其他必要代碼
}
//vuex
export default new Vuex.Store({
  state: {
    Title: "test",
  },
  mutations: {
    changevalue(state, newTitle) {
      state.Title = newTitle;
    }
  },
  actions: {
    change(context, value) {
      context.commit("changeTitle", value);
    }
  },
});

Action和Mutation類似城丧,都是第二個值才是傳入的值,因為Action是對Mutation的操作豌鹤,所以傳值需要多繞一下亡哄,但是還是可以達到預(yù)期效果的。

8. Module

當(dāng)你的系統(tǒng)非常龐大時傍药,把不同模塊的State和Mutation寫在一起會非常的亂磺平,因此Vuex還提供了模塊化。

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 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

上面代碼是引用Vuex官方文檔的代碼,只需要在引用方法和操作時加上模塊名拐辽,就可以正確讀取到相應(yīng)模塊的值和方法拣挪。

操作方法 非模塊化 模塊化
獲取State this.$store.state.value; this.$store.state.[模塊名].value
mapState ...mapState(['value]) ...mapState(['[模塊名]/value'])
Mutation this.$store.commit('event') this.$store.[模塊名].commit('event')
mapMutation ...mapMutation(['event]) ...mapMutation(['[模塊名]/event'])

Action和Getter類似。

使用webpack批量導(dǎo)入Modules

require.context是webpack的一個用來管理依賴的一個函數(shù)俱诸,使用它可以批量導(dǎo)入菠劝,詳細查看文檔
https://webpack.docschina.org/guides/dependency-management/#require-context

具體使用:

import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";
Vue.use(Vuex);

// 引入modules下的所有文件
const modulesFiles = require.context("./modules", false, /\.js$/);

const modules = modulesFiles.keys().reduce((modules, path) => {
  // ./app.js => app
  const name = path.replace(/^\.\/(.*)\.\w+$/, "$1");
  // 如果文件是空的則,下面這句取不出來結(jié)果
  const value = modulesFiles(path);
  modules[name] = value.default;
  return modules;
}, {});
const store = new Vuex.Store({
  modules,
  getters
});
export default store;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末睁搭,一起剝皮案震驚了整個濱河市赶诊,隨后出現(xiàn)的幾起案子笼平,更是在濱河造成了極大的恐慌,老刑警劉巖舔痪,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寓调,死亡現(xiàn)場離奇詭異,居然都是意外死亡锄码,警方通過查閱死者的電腦和手機夺英,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滋捶,“玉大人痛悯,你說我怎么就攤上這事≈乜撸” “怎么了载萌?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長巡扇。 經(jīng)常有香客問我扭仁,道長,這世上最難降的妖魔是什么霎迫? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任斋枢,我火速辦了婚禮,結(jié)果婚禮上知给,老公的妹妹穿的比我還像新娘。我一直安慰自己描姚,他們只是感情好涩赢,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著轩勘,像睡著了一般筒扒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绊寻,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天花墩,我揣著相機與錄音,去河邊找鬼澄步。 笑死冰蘑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的村缸。 我是一名探鬼主播祠肥,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梯皿!你這毒婦竟也來了仇箱?” 一聲冷哼從身側(cè)響起县恕,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剂桥,沒想到半個月后忠烛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡权逗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年况木,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旬迹。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡火惊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奔垦,到底是詐尸還是另有隱情屹耐,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布椿猎,位于F島的核電站惶岭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏犯眠。R本人自食惡果不足惜按灶,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筐咧。 院中可真熱鬧鸯旁,春花似錦、人聲如沸量蕊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽残炮。三九已至韭赘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間势就,已是汗流浹背泉瞻。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留苞冯,地道東北人袖牙。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像抱完,于是被迫代替她去往敵國和親贼陶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容